diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/AssemblyVersionInfo.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/AssemblyVersionInfo.cs index 5187d3fa..73fd3191 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/AssemblyVersionInfo.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/AssemblyVersionInfo.cs @@ -21,7 +21,7 @@ internal static class _XceedVersionInfo { [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] - public const string BaseVersion = "3.2"; + public const string BaseVersion = "3.3"; [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] public const string Version = BaseVersion + ".0.0"; diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/Properties/AssemblyInfo.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/Properties/AssemblyInfo.cs index f8dc5d77..46576551 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/Properties/AssemblyInfo.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/Properties/AssemblyInfo.cs @@ -30,7 +30,7 @@ using System; [assembly: AssemblyCompany( "Xceed Software Inc." )] [assembly: AssemblyProduct( "Xceed Toolkit for WPF - AvalonDock" )] -[assembly: AssemblyCopyright( "Copyright (C) Xceed Software Inc. 2007-2016" )] +[assembly: AssemblyCopyright( "Copyright (C) Xceed Software Inc. 2007-2017" )] diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/Theme.xaml b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/Theme.xaml index 6a38a1ff..83b47b28 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/Theme.xaml +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/Theme.xaml @@ -14,1306 +14,1774 @@ **********************************************************************************--> - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/Brushes.baml b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/Brushes.baml new file mode 100644 index 00000000..6e1c9b10 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/Brushes.baml differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/GeneratedInternalTypeHelper.g.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/GeneratedInternalTypeHelper.g.cs new file mode 100644 index 00000000..c65238fb --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/GeneratedInternalTypeHelper.g.cs @@ -0,0 +1,2 @@ + + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/GeneratedInternalTypeHelper.g.i.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/GeneratedInternalTypeHelper.g.i.cs new file mode 100644 index 00000000..136dd1ba --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/GeneratedInternalTypeHelper.g.i.cs @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace XamlGeneratedNamespace { + + + /// + /// GeneratedInternalTypeHelper + /// + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public sealed class GeneratedInternalTypeHelper : System.Windows.Markup.InternalTypeHelper { + + /// + /// CreateInstance + /// + protected override object CreateInstance(System.Type type, System.Globalization.CultureInfo culture) { + return System.Activator.CreateInstance(type, ((System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic) + | (System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.CreateInstance)), null, null, culture); + } + + /// + /// GetPropertyValue + /// + protected override object GetPropertyValue(System.Reflection.PropertyInfo propertyInfo, object target, System.Globalization.CultureInfo culture) { + return propertyInfo.GetValue(target, System.Reflection.BindingFlags.Default, null, null, culture); + } + + /// + /// SetPropertyValue + /// + protected override void SetPropertyValue(System.Reflection.PropertyInfo propertyInfo, object target, object value, System.Globalization.CultureInfo culture) { + propertyInfo.SetValue(target, value, System.Reflection.BindingFlags.Default, null, null, culture); + } + + /// + /// CreateDelegate + /// + protected override System.Delegate CreateDelegate(System.Type delegateType, object target, string handler) { + return ((System.Delegate)(target.GetType().InvokeMember("_CreateDelegate", (System.Reflection.BindingFlags.InvokeMethod + | (System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)), null, target, new object[] { + delegateType, + handler}, null))); + } + + /// + /// AddEventHandler + /// + protected override void AddEventHandler(System.Reflection.EventInfo eventInfo, object target, System.Delegate handler) { + eventInfo.AddEventHandler(target, handler); + } + } +} + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/Theme.baml b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/Theme.baml new file mode 100644 index 00000000..6727bc1a Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/Theme.baml differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Aero.csproj.FileListAbsolute.txt b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Aero.csproj.FileListAbsolute.txt new file mode 100644 index 00000000..ca7da23f --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Aero.csproj.FileListAbsolute.txt @@ -0,0 +1,23 @@ +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Debug\Xceed.Wpf.AvalonDock.Themes.Aero.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Debug\Xceed.Wpf.AvalonDock.Themes.Aero.pdb +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Debug\Xceed.Wpf.AvalonDock.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Debug\Xceed.Wpf.AvalonDock.pdb +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Debug\de\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Debug\es\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Debug\fr\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Debug\hu\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Debug\it\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Debug\pt-BR\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Debug\ro\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Debug\ru\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Debug\sv\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Debug\zh-Hans\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Debug\Xceed.Wpf.AvalonDock.Themes.Aero.csprojResolveAssemblyReference.cache +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Debug\GeneratedInternalTypeHelper.g.cs +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Debug\Xceed.Wpf.AvalonDock.Themes.Aero_MarkupCompile.cache +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Debug\Xceed.Wpf.AvalonDock.Themes.Aero_MarkupCompile.lref +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Debug\Brushes.baml +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Debug\Theme.baml +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Debug\Xceed.Wpf.AvalonDock.Themes.Aero.g.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Debug\Xceed.Wpf.AvalonDock.Themes.Aero.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Debug\Xceed.Wpf.AvalonDock.Themes.Aero.pdb diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Aero.g.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Aero.g.resources new file mode 100644 index 00000000..a2ba5ff5 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Aero.g.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Aero_MarkupCompile.i.lref b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Aero_MarkupCompile.i.lref new file mode 100644 index 00000000..161cff3a --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Aero_MarkupCompile.i.lref @@ -0,0 +1,5 @@ +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Debug\GeneratedInternalTypeHelper.g.i.cs + +FD:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\Brushes.xaml;; +FD:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\Theme.xaml;; + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Aero_MarkupCompile.lref b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Aero_MarkupCompile.lref new file mode 100644 index 00000000..b21b8ca9 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Aero_MarkupCompile.lref @@ -0,0 +1,5 @@ +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Debug\GeneratedInternalTypeHelper.g.cs + +FD:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\Brushes.xaml;; +FD:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\Theme.xaml;; + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/Brushes.baml b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/Brushes.baml new file mode 100644 index 00000000..16b4ecd6 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/Brushes.baml differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/GeneratedInternalTypeHelper.g.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/GeneratedInternalTypeHelper.g.cs new file mode 100644 index 00000000..c65238fb --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/GeneratedInternalTypeHelper.g.cs @@ -0,0 +1,2 @@ + + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/GeneratedInternalTypeHelper.g.i.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/GeneratedInternalTypeHelper.g.i.cs new file mode 100644 index 00000000..136dd1ba --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/GeneratedInternalTypeHelper.g.i.cs @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace XamlGeneratedNamespace { + + + /// + /// GeneratedInternalTypeHelper + /// + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public sealed class GeneratedInternalTypeHelper : System.Windows.Markup.InternalTypeHelper { + + /// + /// CreateInstance + /// + protected override object CreateInstance(System.Type type, System.Globalization.CultureInfo culture) { + return System.Activator.CreateInstance(type, ((System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic) + | (System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.CreateInstance)), null, null, culture); + } + + /// + /// GetPropertyValue + /// + protected override object GetPropertyValue(System.Reflection.PropertyInfo propertyInfo, object target, System.Globalization.CultureInfo culture) { + return propertyInfo.GetValue(target, System.Reflection.BindingFlags.Default, null, null, culture); + } + + /// + /// SetPropertyValue + /// + protected override void SetPropertyValue(System.Reflection.PropertyInfo propertyInfo, object target, object value, System.Globalization.CultureInfo culture) { + propertyInfo.SetValue(target, value, System.Reflection.BindingFlags.Default, null, null, culture); + } + + /// + /// CreateDelegate + /// + protected override System.Delegate CreateDelegate(System.Type delegateType, object target, string handler) { + return ((System.Delegate)(target.GetType().InvokeMember("_CreateDelegate", (System.Reflection.BindingFlags.InvokeMethod + | (System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)), null, target, new object[] { + delegateType, + handler}, null))); + } + + /// + /// AddEventHandler + /// + protected override void AddEventHandler(System.Reflection.EventInfo eventInfo, object target, System.Delegate handler) { + eventInfo.AddEventHandler(target, handler); + } + } +} + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/Theme.baml b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/Theme.baml new file mode 100644 index 00000000..c40581ec Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/Theme.baml differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/Xceed.Wpf.AvalonDock.Themes.Aero.csproj.FileListAbsolute.txt b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/Xceed.Wpf.AvalonDock.Themes.Aero.csproj.FileListAbsolute.txt new file mode 100644 index 00000000..a4b763bc --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/Xceed.Wpf.AvalonDock.Themes.Aero.csproj.FileListAbsolute.txt @@ -0,0 +1,23 @@ +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Release\Xceed.Wpf.AvalonDock.Themes.Aero.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Release\Xceed.Wpf.AvalonDock.Themes.Aero.pdb +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Release\Xceed.Wpf.AvalonDock.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Release\Xceed.Wpf.AvalonDock.pdb +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Release\de\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Release\es\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Release\fr\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Release\hu\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Release\it\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Release\pt-BR\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Release\ro\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Release\ru\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Release\sv\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\bin\Release\zh-Hans\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Release\Xceed.Wpf.AvalonDock.Themes.Aero.csprojResolveAssemblyReference.cache +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Release\GeneratedInternalTypeHelper.g.cs +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Release\Xceed.Wpf.AvalonDock.Themes.Aero_MarkupCompile.cache +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Release\Xceed.Wpf.AvalonDock.Themes.Aero_MarkupCompile.lref +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Release\Brushes.baml +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Release\Theme.baml +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Release\Xceed.Wpf.AvalonDock.Themes.Aero.g.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Release\Xceed.Wpf.AvalonDock.Themes.Aero.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Release\Xceed.Wpf.AvalonDock.Themes.Aero.pdb diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/Xceed.Wpf.AvalonDock.Themes.Aero.g.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/Xceed.Wpf.AvalonDock.Themes.Aero.g.resources new file mode 100644 index 00000000..62d2180e Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/Xceed.Wpf.AvalonDock.Themes.Aero.g.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/Xceed.Wpf.AvalonDock.Themes.Aero_MarkupCompile.i.lref b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/Xceed.Wpf.AvalonDock.Themes.Aero_MarkupCompile.i.lref new file mode 100644 index 00000000..6775f037 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/Xceed.Wpf.AvalonDock.Themes.Aero_MarkupCompile.i.lref @@ -0,0 +1,5 @@ +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Release\GeneratedInternalTypeHelper.g.i.cs + +FD:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\Brushes.xaml;; +FD:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\Theme.xaml;; + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/Xceed.Wpf.AvalonDock.Themes.Aero_MarkupCompile.lref b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/Xceed.Wpf.AvalonDock.Themes.Aero_MarkupCompile.lref new file mode 100644 index 00000000..0b92f121 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Aero/obj/Release/Xceed.Wpf.AvalonDock.Themes.Aero_MarkupCompile.lref @@ -0,0 +1,5 @@ +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\obj\Release\GeneratedInternalTypeHelper.g.cs + +FD:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\Brushes.xaml;; +FD:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Aero\Theme.xaml;; + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/AssemblyVersionInfo.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/AssemblyVersionInfo.cs index 5187d3fa..73fd3191 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/AssemblyVersionInfo.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/AssemblyVersionInfo.cs @@ -21,7 +21,7 @@ internal static class _XceedVersionInfo { [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] - public const string BaseVersion = "3.2"; + public const string BaseVersion = "3.3"; [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] public const string Version = BaseVersion + ".0.0"; diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Properties/AssemblyInfo.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Properties/AssemblyInfo.cs index fe8545f1..8491c6ba 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Properties/AssemblyInfo.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Properties/AssemblyInfo.cs @@ -30,7 +30,7 @@ using System; [assembly: AssemblyCompany( "Xceed Software Inc." )] [assembly: AssemblyProduct( "Xceed Toolkit for WPF - AvalonDock" )] -[assembly: AssemblyCopyright( "Copyright (C) Xceed Software Inc. 2007-2016" )] +[assembly: AssemblyCopyright( "Copyright (C) Xceed Software Inc. 2007-2017" )] diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Theme.xaml b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Theme.xaml index 769140f8..dbe90ad5 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Theme.xaml +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/Theme.xaml @@ -14,1332 +14,1841 @@ **********************************************************************************--> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + Grid.Column="1" + Grid.Row="1" /> + + + + + + + + + + + + + + + + + - - + + - - + + + + + + + + + + + + + + + - + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Brushes.baml b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Brushes.baml new file mode 100644 index 00000000..2a3b1522 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Brushes.baml differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Theme.baml b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Theme.baml new file mode 100644 index 00000000..e6a5e3c5 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Theme.baml differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.csproj.FileListAbsolute.txt b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.csproj.FileListAbsolute.txt new file mode 100644 index 00000000..180f1b72 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.csproj.FileListAbsolute.txt @@ -0,0 +1,22 @@ +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\Xceed.Wpf.AvalonDock.Themes.Metro.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\Xceed.Wpf.AvalonDock.Themes.Metro.pdb +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\Xceed.Wpf.AvalonDock.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\Xceed.Wpf.AvalonDock.pdb +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\de\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\es\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\fr\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\hu\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\it\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\pt-BR\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\ro\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\ru\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\sv\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Debug\zh-Hans\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Debug\Xceed.Wpf.AvalonDock.Themes.Metro.csprojResolveAssemblyReference.cache +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Debug\Brushes.baml +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Debug\Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.cache +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Debug\Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.lref +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Debug\Theme.baml +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Debug\Xceed.Wpf.AvalonDock.Themes.Metro.g.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Debug\Xceed.Wpf.AvalonDock.Themes.Metro.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Debug\Xceed.Wpf.AvalonDock.Themes.Metro.pdb diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.g.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.g.resources new file mode 100644 index 00000000..da03029f Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro.g.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.i.lref b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.i.lref new file mode 100644 index 00000000..86b39b7f --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.i.lref @@ -0,0 +1,4 @@ + + +FD:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\Theme.xaml;; + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.lref b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.lref new file mode 100644 index 00000000..86b39b7f --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Debug/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.lref @@ -0,0 +1,4 @@ + + +FD:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\Theme.xaml;; + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Release/Brushes.baml b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Release/Brushes.baml new file mode 100644 index 00000000..f9a94fe5 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Release/Brushes.baml differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Release/Theme.baml b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Release/Theme.baml new file mode 100644 index 00000000..f45809ce Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Release/Theme.baml differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Release/Xceed.Wpf.AvalonDock.Themes.Metro.csproj.FileListAbsolute.txt b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Release/Xceed.Wpf.AvalonDock.Themes.Metro.csproj.FileListAbsolute.txt new file mode 100644 index 00000000..e6591c21 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Release/Xceed.Wpf.AvalonDock.Themes.Metro.csproj.FileListAbsolute.txt @@ -0,0 +1,22 @@ +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Release\Xceed.Wpf.AvalonDock.Themes.Metro.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Release\Xceed.Wpf.AvalonDock.Themes.Metro.pdb +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Release\Xceed.Wpf.AvalonDock.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Release\Xceed.Wpf.AvalonDock.pdb +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Release\de\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Release\es\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Release\fr\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Release\hu\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Release\it\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Release\pt-BR\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Release\ro\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Release\ru\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Release\sv\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\bin\Release\zh-Hans\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Release\Xceed.Wpf.AvalonDock.Themes.Metro.csprojResolveAssemblyReference.cache +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Release\Brushes.baml +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Release\Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.cache +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Release\Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.lref +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Release\Theme.baml +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Release\Xceed.Wpf.AvalonDock.Themes.Metro.g.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Release\Xceed.Wpf.AvalonDock.Themes.Metro.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\obj\Release\Xceed.Wpf.AvalonDock.Themes.Metro.pdb diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Release/Xceed.Wpf.AvalonDock.Themes.Metro.g.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Release/Xceed.Wpf.AvalonDock.Themes.Metro.g.resources new file mode 100644 index 00000000..62744a87 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Release/Xceed.Wpf.AvalonDock.Themes.Metro.g.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Release/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.i.lref b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Release/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.i.lref new file mode 100644 index 00000000..86b39b7f --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Release/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.i.lref @@ -0,0 +1,4 @@ + + +FD:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\Theme.xaml;; + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Release/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.lref b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Release/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.lref new file mode 100644 index 00000000..86b39b7f --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.Metro/obj/Release/Xceed.Wpf.AvalonDock.Themes.Metro_MarkupCompile.lref @@ -0,0 +1,4 @@ + + +FD:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.Metro\Theme.xaml;; + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/AssemblyVersionInfo.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/AssemblyVersionInfo.cs index 5187d3fa..73fd3191 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/AssemblyVersionInfo.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/AssemblyVersionInfo.cs @@ -21,7 +21,7 @@ internal static class _XceedVersionInfo { [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] - public const string BaseVersion = "3.2"; + public const string BaseVersion = "3.3"; [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] public const string Version = BaseVersion + ".0.0"; diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/Properties/AssemblyInfo.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/Properties/AssemblyInfo.cs index 39a96798..096508e0 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/Properties/AssemblyInfo.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/Properties/AssemblyInfo.cs @@ -25,12 +25,12 @@ using System; // 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( "Xceed Toolkit for WPF - AvalonDock" )] +[assembly: AssemblyTitle( "Xceed Toolkit for WPF - AvalonDock VS2010 Theme" )] [assembly: AssemblyDescription( "This assembly implements the VS2010 Theme for the AvalonDock layout system." )] [assembly: AssemblyCompany( "Xceed Software Inc." )] [assembly: AssemblyProduct( "Xceed Toolkit for WPF - AvalonDock" )] -[assembly: AssemblyCopyright( "Copyright (C) Xceed Software Inc. 2007-2016" )] +[assembly: AssemblyCopyright( "Copyright (C) Xceed Software Inc. 2007-2017" )] // Setting ComVisible to false makes the types in this assembly not visible diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/Theme.xaml b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/Theme.xaml index a82fec6d..f06a4ef0 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/Theme.xaml +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/Theme.xaml @@ -14,1417 +14,1978 @@ **********************************************************************************--> - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + Grid.Column="1" + Grid.Row="1" /> + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Debug/Brushes.baml b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Debug/Brushes.baml new file mode 100644 index 00000000..1cda146e Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Debug/Brushes.baml differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Debug/Theme.baml b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Debug/Theme.baml new file mode 100644 index 00000000..21afb581 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Debug/Theme.baml differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Debug/Xceed.Wpf.AvalonDock.Themes.VS2010.csproj.FileListAbsolute.txt b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Debug/Xceed.Wpf.AvalonDock.Themes.VS2010.csproj.FileListAbsolute.txt new file mode 100644 index 00000000..970ae804 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Debug/Xceed.Wpf.AvalonDock.Themes.VS2010.csproj.FileListAbsolute.txt @@ -0,0 +1,22 @@ +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Debug\Xceed.Wpf.AvalonDock.Themes.VS2010.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Debug\Xceed.Wpf.AvalonDock.Themes.VS2010.pdb +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Debug\Xceed.Wpf.AvalonDock.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Debug\Xceed.Wpf.AvalonDock.pdb +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Debug\de\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Debug\es\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Debug\fr\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Debug\hu\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Debug\it\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Debug\pt-BR\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Debug\ro\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Debug\ru\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Debug\sv\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Debug\zh-Hans\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\obj\Debug\Xceed.Wpf.AvalonDock.Themes.VS2010.csprojResolveAssemblyReference.cache +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\obj\Debug\Brushes.baml +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\obj\Debug\Xceed.Wpf.AvalonDock.Themes.VS2010_MarkupCompile.cache +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\obj\Debug\Xceed.Wpf.AvalonDock.Themes.VS2010_MarkupCompile.lref +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\obj\Debug\Theme.baml +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\obj\Debug\Xceed.Wpf.AvalonDock.Themes.VS2010.g.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\obj\Debug\Xceed.Wpf.AvalonDock.Themes.VS2010.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\obj\Debug\Xceed.Wpf.AvalonDock.Themes.VS2010.pdb diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Debug/Xceed.Wpf.AvalonDock.Themes.VS2010.g.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Debug/Xceed.Wpf.AvalonDock.Themes.VS2010.g.resources new file mode 100644 index 00000000..f3507144 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Debug/Xceed.Wpf.AvalonDock.Themes.VS2010.g.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Debug/Xceed.Wpf.AvalonDock.Themes.VS2010_MarkupCompile.i.lref b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Debug/Xceed.Wpf.AvalonDock.Themes.VS2010_MarkupCompile.i.lref new file mode 100644 index 00000000..f4e6c70b --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Debug/Xceed.Wpf.AvalonDock.Themes.VS2010_MarkupCompile.i.lref @@ -0,0 +1,4 @@ + + +FD:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\Theme.xaml;; + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Debug/Xceed.Wpf.AvalonDock.Themes.VS2010_MarkupCompile.lref b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Debug/Xceed.Wpf.AvalonDock.Themes.VS2010_MarkupCompile.lref new file mode 100644 index 00000000..f4e6c70b --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Debug/Xceed.Wpf.AvalonDock.Themes.VS2010_MarkupCompile.lref @@ -0,0 +1,4 @@ + + +FD:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\Theme.xaml;; + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Release/Brushes.baml b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Release/Brushes.baml new file mode 100644 index 00000000..140e78f6 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Release/Brushes.baml differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Release/Theme.baml b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Release/Theme.baml new file mode 100644 index 00000000..bc6c6783 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Release/Theme.baml differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Release/Xceed.Wpf.AvalonDock.Themes.VS2010.csproj.FileListAbsolute.txt b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Release/Xceed.Wpf.AvalonDock.Themes.VS2010.csproj.FileListAbsolute.txt new file mode 100644 index 00000000..31cc14f3 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Release/Xceed.Wpf.AvalonDock.Themes.VS2010.csproj.FileListAbsolute.txt @@ -0,0 +1,22 @@ +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Release\Xceed.Wpf.AvalonDock.Themes.VS2010.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Release\Xceed.Wpf.AvalonDock.Themes.VS2010.pdb +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Release\Xceed.Wpf.AvalonDock.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Release\Xceed.Wpf.AvalonDock.pdb +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Release\de\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Release\es\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Release\fr\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Release\hu\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Release\it\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Release\pt-BR\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Release\ro\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Release\ru\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Release\sv\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\bin\Release\zh-Hans\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\obj\Release\Xceed.Wpf.AvalonDock.Themes.VS2010.csprojResolveAssemblyReference.cache +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\obj\Release\Brushes.baml +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\obj\Release\Xceed.Wpf.AvalonDock.Themes.VS2010_MarkupCompile.cache +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\obj\Release\Xceed.Wpf.AvalonDock.Themes.VS2010_MarkupCompile.lref +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\obj\Release\Theme.baml +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\obj\Release\Xceed.Wpf.AvalonDock.Themes.VS2010.g.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\obj\Release\Xceed.Wpf.AvalonDock.Themes.VS2010.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\obj\Release\Xceed.Wpf.AvalonDock.Themes.VS2010.pdb diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Release/Xceed.Wpf.AvalonDock.Themes.VS2010.g.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Release/Xceed.Wpf.AvalonDock.Themes.VS2010.g.resources new file mode 100644 index 00000000..0962fd37 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Release/Xceed.Wpf.AvalonDock.Themes.VS2010.g.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Release/Xceed.Wpf.AvalonDock.Themes.VS2010_MarkupCompile.i.lref b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Release/Xceed.Wpf.AvalonDock.Themes.VS2010_MarkupCompile.i.lref new file mode 100644 index 00000000..f4e6c70b --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Release/Xceed.Wpf.AvalonDock.Themes.VS2010_MarkupCompile.i.lref @@ -0,0 +1,4 @@ + + +FD:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\Theme.xaml;; + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Release/Xceed.Wpf.AvalonDock.Themes.VS2010_MarkupCompile.lref b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Release/Xceed.Wpf.AvalonDock.Themes.VS2010_MarkupCompile.lref new file mode 100644 index 00000000..f4e6c70b --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock.Themes.VS2010/obj/Release/Xceed.Wpf.AvalonDock.Themes.VS2010_MarkupCompile.lref @@ -0,0 +1,4 @@ + + +FD:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock.Themes.VS2010\Theme.xaml;; + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/AssemblyVersionInfo.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/AssemblyVersionInfo.cs index 5187d3fa..73fd3191 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/AssemblyVersionInfo.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/AssemblyVersionInfo.cs @@ -21,7 +21,7 @@ internal static class _XceedVersionInfo { [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] - public const string BaseVersion = "3.2"; + public const string BaseVersion = "3.3"; [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] public const string Version = BaseVersion + ".0.0"; diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorControl.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorControl.cs index 538008f9..d247f9e2 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorControl.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorControl.cs @@ -15,9 +15,6 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Windows; using System.Windows.Controls; using Xceed.Wpf.AvalonDock.Layout; @@ -25,160 +22,165 @@ using System.Windows.Threading; namespace Xceed.Wpf.AvalonDock.Controls { - public class LayoutAnchorControl : Control, ILayoutControl + public class LayoutAnchorControl : Control, ILayoutControl + { + static LayoutAnchorControl() { - static LayoutAnchorControl() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(LayoutAnchorControl), new FrameworkPropertyMetadata(typeof(LayoutAnchorControl))); - Control.IsHitTestVisibleProperty.AddOwner(typeof(LayoutAnchorControl), new FrameworkPropertyMetadata(true)); - } - - - internal LayoutAnchorControl(LayoutAnchorable model) - { - _model = model; - _model.IsActiveChanged += new EventHandler(_model_IsActiveChanged); - _model.IsSelectedChanged += new EventHandler(_model_IsSelectedChanged); - - SetSide(_model.FindParent().Side); - } - - void _model_IsSelectedChanged(object sender, EventArgs e) - { - if (!_model.IsAutoHidden) - _model.IsSelectedChanged -= new EventHandler(_model_IsSelectedChanged); - else if (_model.IsSelected) - { - _model.Root.Manager.ShowAutoHideWindow(this); - _model.IsSelected = false; - } - } - - void _model_IsActiveChanged(object sender, EventArgs e) - { - if (!_model.IsAutoHidden) - _model.IsActiveChanged -= new EventHandler(_model_IsActiveChanged); - else if (_model.IsActive) - _model.Root.Manager.ShowAutoHideWindow(this); - } - - LayoutAnchorable _model; - - public ILayoutElement Model - { - get { return _model; } - } - - //protected override void OnVisualParentChanged(DependencyObject oldParent) - //{ - // base.OnVisualParentChanged(oldParent); - - // var contentModel = _model; - - // if (oldParent != null && contentModel != null && contentModel.Content is UIElement) - // { - // var oldParentPaneControl = oldParent.FindVisualAncestor(); - // if (oldParentPaneControl != null) - // { - // ((ILogicalChildrenContainer)oldParentPaneControl).InternalRemoveLogicalChild(contentModel.Content); - // } - // } - - // if (contentModel.Content != null && contentModel.Content is UIElement) - // { - // var oldLogicalParentPaneControl = LogicalTreeHelper.GetParent(contentModel.Content as UIElement) - // as ILogicalChildrenContainer; - // if (oldLogicalParentPaneControl != null) - // oldLogicalParentPaneControl.InternalRemoveLogicalChild(contentModel.Content); - // } - - // if (contentModel != null && contentModel.Content != null && contentModel.Root != null && contentModel.Content is UIElement) - // { - // ((ILogicalChildrenContainer)contentModel.Root.Manager).InternalAddLogicalChild(contentModel.Content); - // } - //} - - - protected override void OnMouseDown(System.Windows.Input.MouseButtonEventArgs e) - { - base.OnMouseDown(e); - - if (!e.Handled) - { - _model.Root.Manager.ShowAutoHideWindow(this); - _model.IsActive = true; - } - } - - - DispatcherTimer _openUpTimer = null; - - protected override void OnMouseEnter(System.Windows.Input.MouseEventArgs e) - { - base.OnMouseEnter(e); - - if (!e.Handled) - { - _openUpTimer = new DispatcherTimer(DispatcherPriority.ApplicationIdle); - _openUpTimer.Interval = TimeSpan.FromMilliseconds(400); - _openUpTimer.Tick += new EventHandler(_openUpTimer_Tick); - _openUpTimer.Start(); - } - } - - void _openUpTimer_Tick(object sender, EventArgs e) - { - _openUpTimer.Tick -= new EventHandler(_openUpTimer_Tick); - _openUpTimer.Stop(); - _openUpTimer = null; - _model.Root.Manager.ShowAutoHideWindow(this); - } - - protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e) - { - if (_openUpTimer != null) - { - _openUpTimer.Tick -= new EventHandler(_openUpTimer_Tick); - _openUpTimer.Stop(); - _openUpTimer = null; - } - base.OnMouseLeave(e); - } - - - #region Side - - /// - /// Side Read-Only Dependency Property - /// - private static readonly DependencyPropertyKey SidePropertyKey - = DependencyProperty.RegisterReadOnly("Side", typeof(AnchorSide), typeof(LayoutAnchorControl), - new FrameworkPropertyMetadata((AnchorSide)AnchorSide.Left)); - - public static readonly DependencyProperty SideProperty - = SidePropertyKey.DependencyProperty; - - /// - /// Gets the Side property. This dependency property - /// indicates the anchor side of the control. - /// - public AnchorSide Side - { - get { return (AnchorSide)GetValue(SideProperty); } - } - - /// - /// Provides a secure method for setting the Side property. - /// This dependency property indicates the anchor side of the control. - /// - /// The new value for the property. - protected void SetSide(AnchorSide value) - { - SetValue(SidePropertyKey, value); - } - - #endregion + DefaultStyleKeyProperty.OverrideMetadata( typeof( LayoutAnchorControl ), new FrameworkPropertyMetadata( typeof( LayoutAnchorControl ) ) ); + Control.IsHitTestVisibleProperty.AddOwner( typeof( LayoutAnchorControl ), new FrameworkPropertyMetadata( true ) ); + } + + + internal LayoutAnchorControl( LayoutAnchorable model ) + { + _model = model; + _model.IsActiveChanged += new EventHandler( _model_IsActiveChanged ); + _model.IsSelectedChanged += new EventHandler( _model_IsSelectedChanged ); + + SetSide( _model.FindParent().Side ); + } + + void _model_IsSelectedChanged( object sender, EventArgs e ) + { + if( !_model.IsAutoHidden ) + _model.IsSelectedChanged -= new EventHandler( _model_IsSelectedChanged ); + else if( _model.IsSelected ) + { + _model.Root.Manager.ShowAutoHideWindow( this ); + _model.IsSelected = false; + } + } + + void _model_IsActiveChanged( object sender, EventArgs e ) + { + if( !_model.IsAutoHidden ) + _model.IsActiveChanged -= new EventHandler( _model_IsActiveChanged ); + else if( _model.IsActive ) + _model.Root.Manager.ShowAutoHideWindow( this ); + } + + LayoutAnchorable _model; + + public ILayoutElement Model + { + get + { + return _model; + } + } + + //protected override void OnVisualParentChanged(DependencyObject oldParent) + //{ + // base.OnVisualParentChanged(oldParent); + + // var contentModel = _model; + + // if (oldParent != null && contentModel != null && contentModel.Content is UIElement) + // { + // var oldParentPaneControl = oldParent.FindVisualAncestor(); + // if (oldParentPaneControl != null) + // { + // ((ILogicalChildrenContainer)oldParentPaneControl).InternalRemoveLogicalChild(contentModel.Content); + // } + // } + + // if (contentModel.Content != null && contentModel.Content is UIElement) + // { + // var oldLogicalParentPaneControl = LogicalTreeHelper.GetParent(contentModel.Content as UIElement) + // as ILogicalChildrenContainer; + // if (oldLogicalParentPaneControl != null) + // oldLogicalParentPaneControl.InternalRemoveLogicalChild(contentModel.Content); + // } + + // if (contentModel != null && contentModel.Content != null && contentModel.Root != null && contentModel.Content is UIElement) + // { + // ((ILogicalChildrenContainer)contentModel.Root.Manager).InternalAddLogicalChild(contentModel.Content); + // } + //} + + + protected override void OnMouseDown( System.Windows.Input.MouseButtonEventArgs e ) + { + base.OnMouseDown( e ); + + if( !e.Handled ) + { + _model.Root.Manager.ShowAutoHideWindow( this ); + _model.IsActive = true; + } + } + DispatcherTimer _openUpTimer = null; + + protected override void OnMouseEnter( System.Windows.Input.MouseEventArgs e ) + { + base.OnMouseEnter( e ); + + if( !e.Handled ) + { + _openUpTimer = new DispatcherTimer( DispatcherPriority.ApplicationIdle ); + _openUpTimer.Interval = TimeSpan.FromMilliseconds( 400 ); + _openUpTimer.Tick += new EventHandler( _openUpTimer_Tick ); + _openUpTimer.Start(); + } + } + + void _openUpTimer_Tick( object sender, EventArgs e ) + { + _openUpTimer.Tick -= new EventHandler( _openUpTimer_Tick ); + _openUpTimer.Stop(); + _openUpTimer = null; + _model.Root.Manager.ShowAutoHideWindow( this ); + } + + protected override void OnMouseLeave( System.Windows.Input.MouseEventArgs e ) + { + if( _openUpTimer != null ) + { + _openUpTimer.Tick -= new EventHandler( _openUpTimer_Tick ); + _openUpTimer.Stop(); + _openUpTimer = null; + } + base.OnMouseLeave( e ); + } + + + #region Side + + /// + /// Side Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey SidePropertyKey + = DependencyProperty.RegisterReadOnly( "Side", typeof( AnchorSide ), typeof( LayoutAnchorControl ), + new FrameworkPropertyMetadata( ( AnchorSide )AnchorSide.Left ) ); + + public static readonly DependencyProperty SideProperty + = SidePropertyKey.DependencyProperty; + + /// + /// Gets the Side property. This dependency property + /// indicates the anchor side of the control. + /// + public AnchorSide Side + { + get + { + return ( AnchorSide )GetValue( SideProperty ); + } } + + /// + /// Provides a secure method for setting the Side property. + /// This dependency property indicates the anchor side of the control. + /// + /// The new value for the property. + protected void SetSide( AnchorSide value ) + { + SetValue( SidePropertyKey, value ); + } + + #endregion + + } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorSideControl.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorSideControl.cs index 3a3b4f2b..5a0c6e8f 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorSideControl.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorSideControl.cs @@ -15,9 +15,7 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; using System.Linq; -using System.Text; using System.Windows.Controls; using System.Windows; using System.Collections.ObjectModel; @@ -25,228 +23,245 @@ using Xceed.Wpf.AvalonDock.Layout; namespace Xceed.Wpf.AvalonDock.Controls { - public class LayoutAnchorSideControl : Control, ILayoutControl + public class LayoutAnchorSideControl : Control, ILayoutControl + { + static LayoutAnchorSideControl() { - static LayoutAnchorSideControl() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(LayoutAnchorSideControl), new FrameworkPropertyMetadata(typeof(LayoutAnchorSideControl))); - } - + DefaultStyleKeyProperty.OverrideMetadata( typeof( LayoutAnchorSideControl ), new FrameworkPropertyMetadata( typeof( LayoutAnchorSideControl ) ) ); + } - internal LayoutAnchorSideControl(LayoutAnchorSide model) - { - if (model == null) - throw new ArgumentNullException("model"); + internal LayoutAnchorSideControl( LayoutAnchorSide model ) + { + if( model == null ) + throw new ArgumentNullException( "model" ); - _model = model; - CreateChildrenViews(); + _model = model; - _model.Children.CollectionChanged += (s, e) => OnModelChildrenCollectionChanged(e); + CreateChildrenViews(); - UpdateSide(); - } + _model.Children.CollectionChanged += ( s, e ) => OnModelChildrenCollectionChanged( e ); - private void CreateChildrenViews() - { - var manager = _model.Root.Manager; - foreach (var childModel in _model.Children) - { - _childViews.Add(manager.CreateUIElementForModel(childModel) as LayoutAnchorGroupControl); - } - } + UpdateSide(); + } - private void OnModelChildrenCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) - { - if (e.OldItems != null && - (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || - e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace)) - { - foreach (var childModel in e.OldItems) - _childViews.Remove(_childViews.First(cv => cv.Model == childModel)); - } - - if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Reset) - _childViews.Clear(); - - if (e.NewItems != null && - (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || - e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace)) - { - var manager = _model.Root.Manager; - int insertIndex = e.NewStartingIndex; - foreach (LayoutAnchorGroup childModel in e.NewItems) - { - _childViews.Insert(insertIndex++, manager.CreateUIElementForModel(childModel) as LayoutAnchorGroupControl); - } - } - } + private void CreateChildrenViews() + { + var manager = _model.Root.Manager; + foreach( var childModel in _model.Children ) + { + _childViews.Add( manager.CreateUIElementForModel( childModel ) as LayoutAnchorGroupControl ); + } + } - LayoutAnchorSide _model = null; - public ILayoutElement Model + private void OnModelChildrenCollectionChanged( System.Collections.Specialized.NotifyCollectionChangedEventArgs e ) + { + if( e.OldItems != null && + ( e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace ) ) + { + foreach( var childModel in e.OldItems ) + _childViews.Remove( _childViews.First( cv => cv.Model == childModel ) ); + } + + if( e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Reset ) + _childViews.Clear(); + + if( e.NewItems != null && + ( e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace ) ) + { + var manager = _model.Root.Manager; + int insertIndex = e.NewStartingIndex; + foreach( LayoutAnchorGroup childModel in e.NewItems ) { - get { return _model; } + _childViews.Insert( insertIndex++, manager.CreateUIElementForModel( childModel ) as LayoutAnchorGroupControl ); } + } + } - ObservableCollection _childViews = new ObservableCollection(); + LayoutAnchorSide _model = null; + public ILayoutElement Model + { + get + { + return _model; + } + } - public ObservableCollection Children - { - get { return _childViews; } - } + ObservableCollection _childViews = new ObservableCollection(); - void UpdateSide() - { - switch (_model.Side) - { - case AnchorSide.Left: - SetIsLeftSide(true); - break; - case AnchorSide.Top: - SetIsTopSide(true); - break; - case AnchorSide.Right: - SetIsRightSide(true); - break; - case AnchorSide.Bottom: - SetIsBottomSide(true); - break; - } - } + public ObservableCollection Children + { + get + { + return _childViews; + } + } - #region IsLeftSide + void UpdateSide() + { + switch( _model.Side ) + { + case AnchorSide.Left: + SetIsLeftSide( true ); + break; + case AnchorSide.Top: + SetIsTopSide( true ); + break; + case AnchorSide.Right: + SetIsRightSide( true ); + break; + case AnchorSide.Bottom: + SetIsBottomSide( true ); + break; + } + } - /// - /// IsLeftSide Read-Only Dependency Property - /// - private static readonly DependencyPropertyKey IsLeftSidePropertyKey - = DependencyProperty.RegisterReadOnly("IsLeftSide", typeof(bool), typeof(LayoutAnchorSideControl), - new FrameworkPropertyMetadata((bool)false)); + #region IsLeftSide - public static readonly DependencyProperty IsLeftSideProperty - = IsLeftSidePropertyKey.DependencyProperty; + /// + /// IsLeftSide Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey IsLeftSidePropertyKey + = DependencyProperty.RegisterReadOnly( "IsLeftSide", typeof( bool ), typeof( LayoutAnchorSideControl ), + new FrameworkPropertyMetadata( ( bool )false ) ); - /// - /// Gets the IsLeftSide property. This dependency property - /// indicates this control is anchored to left side. - /// - public bool IsLeftSide - { - get { return (bool)GetValue(IsLeftSideProperty); } - } + public static readonly DependencyProperty IsLeftSideProperty + = IsLeftSidePropertyKey.DependencyProperty; - /// - /// Provides a secure method for setting the IsLeftSide property. - /// This dependency property indicates this control is anchored to left side. - /// - /// The new value for the property. - protected void SetIsLeftSide(bool value) - { - SetValue(IsLeftSidePropertyKey, value); - } + /// + /// Gets the IsLeftSide property. This dependency property + /// indicates this control is anchored to left side. + /// + public bool IsLeftSide + { + get + { + return ( bool )GetValue( IsLeftSideProperty ); + } + } - #endregion + /// + /// Provides a secure method for setting the IsLeftSide property. + /// This dependency property indicates this control is anchored to left side. + /// + /// The new value for the property. + protected void SetIsLeftSide( bool value ) + { + SetValue( IsLeftSidePropertyKey, value ); + } - #region IsTopSide + #endregion - /// - /// IsTopSide Read-Only Dependency Property - /// - private static readonly DependencyPropertyKey IsTopSidePropertyKey - = DependencyProperty.RegisterReadOnly("IsTopSide", typeof(bool), typeof(LayoutAnchorSideControl), - new FrameworkPropertyMetadata((bool)false)); + #region IsTopSide - public static readonly DependencyProperty IsTopSideProperty - = IsTopSidePropertyKey.DependencyProperty; + /// + /// IsTopSide Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey IsTopSidePropertyKey + = DependencyProperty.RegisterReadOnly( "IsTopSide", typeof( bool ), typeof( LayoutAnchorSideControl ), + new FrameworkPropertyMetadata( ( bool )false ) ); - /// - /// Gets the IsTopSide property. This dependency property - /// indicates this control is anchored to top side. - /// - public bool IsTopSide - { - get { return (bool)GetValue(IsTopSideProperty); } - } + public static readonly DependencyProperty IsTopSideProperty + = IsTopSidePropertyKey.DependencyProperty; - /// - /// Provides a secure method for setting the IsTopSide property. - /// This dependency property indicates this control is anchored to top side. - /// - /// The new value for the property. - protected void SetIsTopSide(bool value) - { - SetValue(IsTopSidePropertyKey, value); - } + /// + /// Gets the IsTopSide property. This dependency property + /// indicates this control is anchored to top side. + /// + public bool IsTopSide + { + get + { + return ( bool )GetValue( IsTopSideProperty ); + } + } - #endregion + /// + /// Provides a secure method for setting the IsTopSide property. + /// This dependency property indicates this control is anchored to top side. + /// + /// The new value for the property. + protected void SetIsTopSide( bool value ) + { + SetValue( IsTopSidePropertyKey, value ); + } - #region IsRightSide + #endregion - /// - /// IsRightSide Read-Only Dependency Property - /// - private static readonly DependencyPropertyKey IsRightSidePropertyKey - = DependencyProperty.RegisterReadOnly("IsRightSide", typeof(bool), typeof(LayoutAnchorSideControl), - new FrameworkPropertyMetadata((bool)false)); + #region IsRightSide - public static readonly DependencyProperty IsRightSideProperty - = IsRightSidePropertyKey.DependencyProperty; + /// + /// IsRightSide Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey IsRightSidePropertyKey + = DependencyProperty.RegisterReadOnly( "IsRightSide", typeof( bool ), typeof( LayoutAnchorSideControl ), + new FrameworkPropertyMetadata( ( bool )false ) ); - /// - /// Gets the IsRightSide property. This dependency property - /// indicates this control is anchored to right side. - /// - public bool IsRightSide - { - get { return (bool)GetValue(IsRightSideProperty); } - } + public static readonly DependencyProperty IsRightSideProperty + = IsRightSidePropertyKey.DependencyProperty; - /// - /// Provides a secure method for setting the IsRightSide property. - /// This dependency property indicates this control is anchored to right side. - /// - /// The new value for the property. - protected void SetIsRightSide(bool value) - { - SetValue(IsRightSidePropertyKey, value); - } + /// + /// Gets the IsRightSide property. This dependency property + /// indicates this control is anchored to right side. + /// + public bool IsRightSide + { + get + { + return ( bool )GetValue( IsRightSideProperty ); + } + } - #endregion + /// + /// Provides a secure method for setting the IsRightSide property. + /// This dependency property indicates this control is anchored to right side. + /// + /// The new value for the property. + protected void SetIsRightSide( bool value ) + { + SetValue( IsRightSidePropertyKey, value ); + } - #region IsBottomSide + #endregion - /// - /// IsBottomSide Read-Only Dependency Property - /// - private static readonly DependencyPropertyKey IsBottomSidePropertyKey - = DependencyProperty.RegisterReadOnly("IsBottomSide", typeof(bool), typeof(LayoutAnchorSideControl), - new FrameworkPropertyMetadata((bool)false)); + #region IsBottomSide - public static readonly DependencyProperty IsBottomSideProperty - = IsBottomSidePropertyKey.DependencyProperty; + /// + /// IsBottomSide Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey IsBottomSidePropertyKey + = DependencyProperty.RegisterReadOnly( "IsBottomSide", typeof( bool ), typeof( LayoutAnchorSideControl ), + new FrameworkPropertyMetadata( ( bool )false ) ); - /// - /// Gets the IsBottomSide property. This dependency property - /// indicates if this panel is anchored to bottom side. - /// - public bool IsBottomSide - { - get { return (bool)GetValue(IsBottomSideProperty); } - } + public static readonly DependencyProperty IsBottomSideProperty + = IsBottomSidePropertyKey.DependencyProperty; - /// - /// Provides a secure method for setting the IsBottomSide property. - /// This dependency property indicates if this panel is anchored to bottom side. - /// - /// The new value for the property. - protected void SetIsBottomSide(bool value) - { - SetValue(IsBottomSidePropertyKey, value); - } + /// + /// Gets the IsBottomSide property. This dependency property + /// indicates if this panel is anchored to bottom side. + /// + public bool IsBottomSide + { + get + { + return ( bool )GetValue( IsBottomSideProperty ); + } + } - #endregion + /// + /// Provides a secure method for setting the IsBottomSide property. + /// This dependency property indicates if this panel is anchored to bottom side. + /// + /// The new value for the property. + protected void SetIsBottomSide( bool value ) + { + SetValue( IsBottomSidePropertyKey, value ); + } + #endregion - } + } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableControl.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableControl.cs index 4e616266..f4bd9a32 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableControl.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableControl.cs @@ -14,147 +14,144 @@ ***********************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Windows; using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; using Xceed.Wpf.AvalonDock.Layout; namespace Xceed.Wpf.AvalonDock.Controls { - public class LayoutAnchorableControl : Control + public class LayoutAnchorableControl : Control + { + static LayoutAnchorableControl() { - static LayoutAnchorableControl() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(LayoutAnchorableControl), new FrameworkPropertyMetadata(typeof(LayoutAnchorableControl))); - FocusableProperty.OverrideMetadata(typeof(LayoutAnchorableControl), new FrameworkPropertyMetadata(false)); - } - - public LayoutAnchorableControl() - { - //SetBinding(FlowDirectionProperty, new Binding("Model.Root.Manager.FlowDirection") { Source = this }); - } + DefaultStyleKeyProperty.OverrideMetadata( typeof( LayoutAnchorableControl ), new FrameworkPropertyMetadata( typeof( LayoutAnchorableControl ) ) ); + FocusableProperty.OverrideMetadata( typeof( LayoutAnchorableControl ), new FrameworkPropertyMetadata( false ) ); + } + public LayoutAnchorableControl() + { + //SetBinding(FlowDirectionProperty, new Binding("Model.Root.Manager.FlowDirection") { Source = this }); + } - #region Model - /// - /// Model Dependency Property - /// - public static readonly DependencyProperty ModelProperty = - DependencyProperty.Register("Model", typeof(LayoutAnchorable), typeof(LayoutAnchorableControl), - new FrameworkPropertyMetadata((LayoutAnchorable)null, - new PropertyChangedCallback(OnModelChanged))); + #region Model - /// - /// Gets or sets the Model property. This dependency property - /// indicates the model attached to this view. - /// - public LayoutAnchorable Model - { - get { return (LayoutAnchorable)GetValue(ModelProperty); } - set { SetValue(ModelProperty, value); } - } + /// + /// Model Dependency Property + /// + public static readonly DependencyProperty ModelProperty = + DependencyProperty.Register( "Model", typeof( LayoutAnchorable ), typeof( LayoutAnchorableControl ), + new FrameworkPropertyMetadata( ( LayoutAnchorable )null, + new PropertyChangedCallback( OnModelChanged ) ) ); - /// - /// Handles changes to the Model property. - /// - private static void OnModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((LayoutAnchorableControl)d).OnModelChanged(e); - } + /// + /// Gets or sets the Model property. This dependency property + /// indicates the model attached to this view. + /// + public LayoutAnchorable Model + { + get + { + return ( LayoutAnchorable )GetValue( ModelProperty ); + } + set + { + SetValue( ModelProperty, value ); + } + } - /// - /// Provides derived classes an opportunity to handle changes to the Model property. - /// - protected virtual void OnModelChanged(DependencyPropertyChangedEventArgs e) - { - if( e.OldValue != null ) - { - ((LayoutContent)e.OldValue).PropertyChanged -= Model_PropertyChanged; - } + /// + /// Handles changes to the Model property. + /// + private static void OnModelChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutAnchorableControl )d ).OnModelChanged( e ); + } - if( Model != null ) - { - Model.PropertyChanged += Model_PropertyChanged; - SetLayoutItem( Model.Root.Manager.GetLayoutItemFromModel( Model ) ); - } - else - SetLayoutItem( null ); - } + /// + /// Provides derived classes an opportunity to handle changes to the Model property. + /// + protected virtual void OnModelChanged( DependencyPropertyChangedEventArgs e ) + { + if( e.OldValue != null ) + { + ( ( LayoutContent )e.OldValue ).PropertyChanged -= Model_PropertyChanged; + } + + if( Model != null ) + { + Model.PropertyChanged += Model_PropertyChanged; + SetLayoutItem( Model.Root.Manager.GetLayoutItemFromModel( Model ) ); + } + else + SetLayoutItem( null ); + } - private void Model_PropertyChanged( object sender, System.ComponentModel.PropertyChangedEventArgs e ) + private void Model_PropertyChanged( object sender, System.ComponentModel.PropertyChangedEventArgs e ) + { + if( e.PropertyName == "IsEnabled" ) + { + if( Model != null ) { - if( e.PropertyName == "IsEnabled" ) + IsEnabled = Model.IsEnabled; + if( !IsEnabled && Model.IsActive ) { - if( Model != null ) + if( ( Model.Parent != null ) && ( Model.Parent is LayoutAnchorablePane ) ) { - IsEnabled = Model.IsEnabled; - if( !IsEnabled && Model.IsActive ) - { - if( (Model.Parent != null) && (Model.Parent is LayoutAnchorablePane) ) - { - ((LayoutAnchorablePane)Model.Parent).SetNextSelectedIndex(); - } - } + ( ( LayoutAnchorablePane )Model.Parent ).SetNextSelectedIndex(); } } } + } + } - #endregion + #endregion - #region LayoutItem + #region LayoutItem - /// - /// LayoutItem Read-Only Dependency Property - /// - private static readonly DependencyPropertyKey LayoutItemPropertyKey - = DependencyProperty.RegisterReadOnly("LayoutItem", typeof(LayoutItem), typeof(LayoutAnchorableControl), - new FrameworkPropertyMetadata((LayoutItem)null)); + /// + /// LayoutItem Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey LayoutItemPropertyKey + = DependencyProperty.RegisterReadOnly( "LayoutItem", typeof( LayoutItem ), typeof( LayoutAnchorableControl ), + new FrameworkPropertyMetadata( ( LayoutItem )null ) ); - public static readonly DependencyProperty LayoutItemProperty - = LayoutItemPropertyKey.DependencyProperty; + public static readonly DependencyProperty LayoutItemProperty + = LayoutItemPropertyKey.DependencyProperty; - /// - /// Gets the LayoutItem property. This dependency property - /// indicates the LayoutItem attached to this tag item. - /// - public LayoutItem LayoutItem - { - get { return (LayoutItem)GetValue(LayoutItemProperty); } - } - - /// - /// Provides a secure method for setting the LayoutItem property. - /// This dependency property indicates the LayoutItem attached to this tag item. - /// - /// The new value for the property. - protected void SetLayoutItem(LayoutItem value) - { - SetValue(LayoutItemPropertyKey, value); - } + /// + /// Gets the LayoutItem property. This dependency property + /// indicates the LayoutItem attached to this tag item. + /// + public LayoutItem LayoutItem + { + get + { + return ( LayoutItem )GetValue( LayoutItemProperty ); + } + } - #endregion + /// + /// Provides a secure method for setting the LayoutItem property. + /// This dependency property indicates the LayoutItem attached to this tag item. + /// + /// The new value for the property. + protected void SetLayoutItem( LayoutItem value ) + { + SetValue( LayoutItemPropertyKey, value ); + } + #endregion - protected override void OnGotKeyboardFocus(System.Windows.Input.KeyboardFocusChangedEventArgs e) - { - if (Model != null) - Model.IsActive = true; - base.OnGotKeyboardFocus(e); - } + protected override void OnGotKeyboardFocus( System.Windows.Input.KeyboardFocusChangedEventArgs e ) + { + if( Model != null ) + Model.IsActive = true; + base.OnGotKeyboardFocus( e ); + } - } + } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableFloatingWindowControl.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableFloatingWindowControl.cs index 4dee8d5c..a6746b40 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableFloatingWindowControl.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorableFloatingWindowControl.cs @@ -47,6 +47,7 @@ namespace Xceed.Wpf.AvalonDock.Controls { _model = model; HideWindowCommand = new RelayCommand( ( p ) => OnExecuteHideWindowCommand( p ), ( p ) => CanExecuteHideWindowCommand( p ) ); + CloseWindowCommand = new RelayCommand( ( p ) => OnExecuteCloseWindowCommand( p ), ( p ) => CanExecuteCloseWindowCommand( p ) ); UpdateThemeResources(); } @@ -362,5 +363,60 @@ namespace Xceed.Wpf.AvalonDock.Controls } } #endregion + + #region CloseWindowCommand + public ICommand CloseWindowCommand + { + get; + private set; + } + + private bool CanExecuteCloseWindowCommand( object parameter ) + { + if( Model == null ) + return false; + + var root = Model.Root; + if( root == null ) + return false; + + var manager = root.Manager; + if( manager == null ) + return false; + + bool canExecute = false; + foreach( var anchorable in this.Model.Descendents().OfType().ToArray() ) + { + if( !anchorable.CanClose ) + { + canExecute = false; + break; + } + + var anchorableLayoutItem = manager.GetLayoutItemFromModel( anchorable ) as LayoutAnchorableItem; + if( anchorableLayoutItem == null || + anchorableLayoutItem.CloseCommand == null || + !anchorableLayoutItem.CloseCommand.CanExecute( parameter ) ) + { + canExecute = false; + break; + } + + canExecute = true; + } + + return canExecute; + } + + private void OnExecuteCloseWindowCommand( object parameter ) + { + var manager = Model.Root.Manager; + foreach( var anchorable in this.Model.Descendents().OfType().ToArray() ) + { + var anchorableLayoutItem = manager.GetLayoutItemFromModel( anchorable ) as LayoutAnchorableItem; + anchorableLayoutItem.CloseCommand.Execute( parameter ); + } + } + #endregion } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorablePaneControl.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorablePaneControl.cs index 048554c0..651a6592 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorablePaneControl.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAnchorablePaneControl.cs @@ -15,10 +15,6 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Collections.ObjectModel; using System.Windows.Controls; using System.Windows; using System.Windows.Data; @@ -94,5 +90,4 @@ namespace Xceed.Wpf.AvalonDock.Controls } } - } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAutoHideWindowControl.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAutoHideWindowControl.cs index 5310d66f..f2216a90 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAutoHideWindowControl.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutAutoHideWindowControl.cs @@ -15,9 +15,7 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; using System.Linq; -using System.Text; using System.Windows.Interop; using System.Windows.Controls; using System.Runtime.InteropServices; @@ -26,527 +24,542 @@ using System.Windows.Input; using System.Windows.Data; using System.Windows.Media; using Xceed.Wpf.AvalonDock.Layout; -using System.Diagnostics; -using System.Windows.Threading; namespace Xceed.Wpf.AvalonDock.Controls { - public class LayoutAutoHideWindowControl : HwndHost, ILayoutControl + public class LayoutAutoHideWindowControl : HwndHost, ILayoutControl + { + static LayoutAutoHideWindowControl() { - static LayoutAutoHideWindowControl() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(LayoutAutoHideWindowControl), new FrameworkPropertyMetadata(typeof(LayoutAutoHideWindowControl))); - UIElement.FocusableProperty.OverrideMetadata(typeof(LayoutAutoHideWindowControl), new FrameworkPropertyMetadata(true)); - Control.IsTabStopProperty.OverrideMetadata(typeof(LayoutAutoHideWindowControl), new FrameworkPropertyMetadata(true)); - VisibilityProperty.OverrideMetadata(typeof(LayoutAutoHideWindowControl), new FrameworkPropertyMetadata(Visibility.Hidden)); - } + DefaultStyleKeyProperty.OverrideMetadata( typeof( LayoutAutoHideWindowControl ), new FrameworkPropertyMetadata( typeof( LayoutAutoHideWindowControl ) ) ); + UIElement.FocusableProperty.OverrideMetadata( typeof( LayoutAutoHideWindowControl ), new FrameworkPropertyMetadata( true ) ); + Control.IsTabStopProperty.OverrideMetadata( typeof( LayoutAutoHideWindowControl ), new FrameworkPropertyMetadata( true ) ); + VisibilityProperty.OverrideMetadata( typeof( LayoutAutoHideWindowControl ), new FrameworkPropertyMetadata( Visibility.Hidden ) ); + } - internal LayoutAutoHideWindowControl() - { - } + internal LayoutAutoHideWindowControl() + { + } - internal void Show(LayoutAnchorControl anchor) - { - if (_model != null) - throw new InvalidOperationException(); + internal void Show( LayoutAnchorControl anchor ) + { + if( _model != null ) + throw new InvalidOperationException(); - _anchor = anchor; - _model = anchor.Model as LayoutAnchorable; - _side = (anchor.Model.Parent.Parent as LayoutAnchorSide).Side; - _manager = _model.Root.Manager; - CreateInternalGrid(); + _anchor = anchor; + _model = anchor.Model as LayoutAnchorable; + _side = ( anchor.Model.Parent.Parent as LayoutAnchorSide ).Side; + _manager = _model.Root.Manager; + CreateInternalGrid(); - _model.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(_model_PropertyChanged); + _model.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler( _model_PropertyChanged ); - Visibility = System.Windows.Visibility.Visible; - InvalidateMeasure(); - UpdateWindowPos(); - } + Visibility = System.Windows.Visibility.Visible; + InvalidateMeasure(); + UpdateWindowPos(); + } - internal void Hide() - { - if (_model == null) - return; + internal void Hide() + { + if( _model == null ) + return; - _model.PropertyChanged -= new System.ComponentModel.PropertyChangedEventHandler(_model_PropertyChanged); + _model.PropertyChanged -= new System.ComponentModel.PropertyChangedEventHandler( _model_PropertyChanged ); - RemoveInternalGrid(); - _anchor = null; - _model = null; - _manager = null; - Visibility = System.Windows.Visibility.Hidden; - } + RemoveInternalGrid(); + _anchor = null; + _model = null; + _manager = null; + Visibility = System.Windows.Visibility.Hidden; + } - LayoutAnchorControl _anchor; + LayoutAnchorControl _anchor; - LayoutAnchorable _model; + LayoutAnchorable _model; - public ILayoutElement Model - { - get { return _model; } - } + public ILayoutElement Model + { + get + { + return _model; + } + } - HwndSource _internalHwndSource = null; - IntPtr parentWindowHandle; - protected override System.Runtime.InteropServices.HandleRef BuildWindowCore(System.Runtime.InteropServices.HandleRef hwndParent) - { - parentWindowHandle = hwndParent.Handle; - _internalHwndSource = new HwndSource(new HwndSourceParameters() - { - ParentWindow = hwndParent.Handle, - WindowStyle = Win32Helper.WS_CHILD | Win32Helper.WS_VISIBLE | Win32Helper.WS_CLIPSIBLINGS | Win32Helper.WS_CLIPCHILDREN, - Width = 0, - Height = 0, - }); - - //_internalHost_ContentRendered = false; - _internalHwndSource.ContentRendered += _internalHwndSource_ContentRendered; - _internalHwndSource.RootVisual = _internalHostPresenter; - AddLogicalChild(_internalHostPresenter); - Win32Helper.BringWindowToTop(_internalHwndSource.Handle); - return new HandleRef(this, _internalHwndSource.Handle); - } + HwndSource _internalHwndSource = null; + IntPtr parentWindowHandle; + protected override System.Runtime.InteropServices.HandleRef BuildWindowCore( System.Runtime.InteropServices.HandleRef hwndParent ) + { + parentWindowHandle = hwndParent.Handle; + _internalHwndSource = new HwndSource( new HwndSourceParameters() + { + ParentWindow = hwndParent.Handle, + WindowStyle = Win32Helper.WS_CHILD | Win32Helper.WS_VISIBLE | Win32Helper.WS_CLIPSIBLINGS | Win32Helper.WS_CLIPCHILDREN, + Width = 0, + Height = 0, + } ); + + _internalHost_ContentRendered = false; + _internalHwndSource.ContentRendered += _internalHwndSource_ContentRendered; + _internalHwndSource.RootVisual = _internalHostPresenter; + AddLogicalChild( _internalHostPresenter ); + Win32Helper.BringWindowToTop( _internalHwndSource.Handle ); + return new HandleRef( this, _internalHwndSource.Handle ); + } - // private bool _internalHost_ContentRendered = false; + private bool _internalHost_ContentRendered = false; - void _internalHwndSource_ContentRendered(object sender, EventArgs e) - { - // _internalHost_ContentRendered = true; - } + void _internalHwndSource_ContentRendered( object sender, EventArgs e ) + { + _internalHost_ContentRendered = true; + } - //protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) - //{ - // if (msg == Win32Helper.WM_WINDOWPOSCHANGING) - // { - // if (_internalHost_ContentRendered) - // Win32Helper.SetWindowPos(_internalHwndSource.Handle, Win32Helper.HWND_TOP, 0, 0, 0, 0, Win32Helper.SetWindowPosFlags.IgnoreMove | Win32Helper.SetWindowPosFlags.IgnoreResize); - // } - // return base.WndProc(hwnd, msg, wParam, lParam, ref handled); - //} + protected override IntPtr WndProc( IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled ) + { + if( msg == Win32Helper.WM_WINDOWPOSCHANGING ) + { + if( _internalHost_ContentRendered ) + Win32Helper.SetWindowPos( _internalHwndSource.Handle, Win32Helper.HWND_TOP, 0, 0, 0, 0, Win32Helper.SetWindowPosFlags.IgnoreMove | Win32Helper.SetWindowPosFlags.IgnoreResize ); + } + return base.WndProc( hwnd, msg, wParam, lParam, ref handled ); + } - protected override void DestroyWindowCore(System.Runtime.InteropServices.HandleRef hwnd) - { - if (_internalHwndSource != null) - { - _internalHwndSource.ContentRendered -= _internalHwndSource_ContentRendered; - _internalHwndSource.Dispose(); - _internalHwndSource = null; - } - } + protected override void DestroyWindowCore( System.Runtime.InteropServices.HandleRef hwnd ) + { + if( _internalHwndSource != null ) + { + _internalHwndSource.ContentRendered -= _internalHwndSource_ContentRendered; + _internalHwndSource.Dispose(); + _internalHwndSource = null; + } + } - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); - } + } - ContentPresenter _internalHostPresenter = new ContentPresenter(); - Grid _internalGrid = null; - LayoutAnchorableControl _internalHost = null; - AnchorSide _side; - LayoutGridResizerControl _resizer = null; - DockingManager _manager; + ContentPresenter _internalHostPresenter = new ContentPresenter(); + Grid _internalGrid = null; + internal LayoutAnchorableControl _internalHost = null; + AnchorSide _side; + LayoutGridResizerControl _resizer = null; + DockingManager _manager; - void _model_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + void _model_PropertyChanged( object sender, System.ComponentModel.PropertyChangedEventArgs e ) + { + if( e.PropertyName == "IsAutoHidden" ) + { + if( !_model.IsAutoHidden ) { - if (e.PropertyName == "IsAutoHidden") - { - if (!_model.IsAutoHidden) - { - _manager.HideAutoHideWindow(_anchor); - } - } + _manager.HideAutoHideWindow( _anchor ); } + } + } - void CreateInternalGrid() - { - _internalGrid = new Grid() { FlowDirection = System.Windows.FlowDirection.LeftToRight}; - _internalGrid.SetBinding(Grid.BackgroundProperty, new Binding("Background") { Source = this }); + void CreateInternalGrid() + { + _internalGrid = new Grid() { FlowDirection = System.Windows.FlowDirection.LeftToRight }; + _internalGrid.SetBinding( Grid.BackgroundProperty, new Binding( "Background" ) { Source = this } ); - _internalHost = new LayoutAnchorableControl() { Model = _model, Style = AnchorableStyle }; - _internalHost.SetBinding(FlowDirectionProperty, new Binding("Model.Root.Manager.FlowDirection") { Source = this }); + _internalHost = new LayoutAnchorableControl() { Model = _model, Style = AnchorableStyle }; + _internalHost.SetBinding( FlowDirectionProperty, new Binding( "Model.Root.Manager.FlowDirection" ) { Source = this } ); - KeyboardNavigation.SetTabNavigation(_internalGrid, KeyboardNavigationMode.Cycle); + KeyboardNavigation.SetTabNavigation( _internalGrid, KeyboardNavigationMode.Cycle ); - _resizer = new LayoutGridResizerControl(); + _resizer = new LayoutGridResizerControl(); - _resizer.DragStarted += new System.Windows.Controls.Primitives.DragStartedEventHandler(OnResizerDragStarted); - _resizer.DragDelta += new System.Windows.Controls.Primitives.DragDeltaEventHandler(OnResizerDragDelta); - _resizer.DragCompleted += new System.Windows.Controls.Primitives.DragCompletedEventHandler(OnResizerDragCompleted); + _resizer.DragStarted += new System.Windows.Controls.Primitives.DragStartedEventHandler( OnResizerDragStarted ); + _resizer.DragDelta += new System.Windows.Controls.Primitives.DragDeltaEventHandler( OnResizerDragDelta ); + _resizer.DragCompleted += new System.Windows.Controls.Primitives.DragCompletedEventHandler( OnResizerDragCompleted ); - if (_side == AnchorSide.Right) - { - _internalGrid.ColumnDefinitions.Add(new ColumnDefinition(){ Width = new GridLength(_manager.GridSplitterWidth)}); - _internalGrid.ColumnDefinitions.Add(new ColumnDefinition(){ - Width = _model.AutoHideWidth == 0.0 ? new GridLength(_model.AutoHideMinWidth) : new GridLength(_model.AutoHideWidth, GridUnitType.Pixel)}); + if( _side == AnchorSide.Right ) + { + _internalGrid.ColumnDefinitions.Add( new ColumnDefinition() { Width = new GridLength( _manager.GridSplitterWidth ) } ); + _internalGrid.ColumnDefinitions.Add( new ColumnDefinition() + { + Width = _model.AutoHideWidth == 0.0 ? new GridLength( _model.AutoHideMinWidth ) : new GridLength( _model.AutoHideWidth, GridUnitType.Pixel ) + } ); - Grid.SetColumn(_resizer, 0); - Grid.SetColumn(_internalHost, 1); + Grid.SetColumn( _resizer, 0 ); + Grid.SetColumn( _internalHost, 1 ); - _resizer.Cursor = Cursors.SizeWE; + _resizer.Cursor = Cursors.SizeWE; - HorizontalAlignment = System.Windows.HorizontalAlignment.Right; - VerticalAlignment = System.Windows.VerticalAlignment.Stretch; - } - else if (_side == AnchorSide.Left) - { - _internalGrid.ColumnDefinitions.Add(new ColumnDefinition() - { - Width = _model.AutoHideWidth == 0.0 ? new GridLength(_model.AutoHideMinWidth) : new GridLength(_model.AutoHideWidth, GridUnitType.Pixel), - }); - _internalGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(_manager.GridSplitterWidth) }); + HorizontalAlignment = System.Windows.HorizontalAlignment.Right; + VerticalAlignment = System.Windows.VerticalAlignment.Stretch; + } + else if( _side == AnchorSide.Left ) + { + _internalGrid.ColumnDefinitions.Add( new ColumnDefinition() + { + Width = _model.AutoHideWidth == 0.0 ? new GridLength( _model.AutoHideMinWidth ) : new GridLength( _model.AutoHideWidth, GridUnitType.Pixel ), + } ); + _internalGrid.ColumnDefinitions.Add( new ColumnDefinition() { Width = new GridLength( _manager.GridSplitterWidth ) } ); - Grid.SetColumn(_internalHost, 0); - Grid.SetColumn(_resizer, 1); + Grid.SetColumn( _internalHost, 0 ); + Grid.SetColumn( _resizer, 1 ); - _resizer.Cursor = Cursors.SizeWE; + _resizer.Cursor = Cursors.SizeWE; - HorizontalAlignment = System.Windows.HorizontalAlignment.Left; - VerticalAlignment = System.Windows.VerticalAlignment.Stretch; - } - else if (_side == AnchorSide.Top) - { - _internalGrid.RowDefinitions.Add(new RowDefinition() - { - Height = _model.AutoHideHeight == 0.0 ? new GridLength(_model.AutoHideMinHeight) : new GridLength(_model.AutoHideHeight, GridUnitType.Pixel), - }); - _internalGrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(_manager.GridSplitterHeight) }); + HorizontalAlignment = System.Windows.HorizontalAlignment.Left; + VerticalAlignment = System.Windows.VerticalAlignment.Stretch; + } + else if( _side == AnchorSide.Top ) + { + _internalGrid.RowDefinitions.Add( new RowDefinition() + { + Height = _model.AutoHideHeight == 0.0 ? new GridLength( _model.AutoHideMinHeight ) : new GridLength( _model.AutoHideHeight, GridUnitType.Pixel ), + } ); + _internalGrid.RowDefinitions.Add( new RowDefinition() { Height = new GridLength( _manager.GridSplitterHeight ) } ); - Grid.SetRow(_internalHost, 0); - Grid.SetRow(_resizer, 1); + Grid.SetRow( _internalHost, 0 ); + Grid.SetRow( _resizer, 1 ); - _resizer.Cursor = Cursors.SizeNS; + _resizer.Cursor = Cursors.SizeNS; - VerticalAlignment = System.Windows.VerticalAlignment.Top; - HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch; + VerticalAlignment = System.Windows.VerticalAlignment.Top; + HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch; - } - else if (_side == AnchorSide.Bottom) - { - _internalGrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(_manager.GridSplitterHeight) }); - _internalGrid.RowDefinitions.Add(new RowDefinition() - { - Height = _model.AutoHideHeight == 0.0 ? new GridLength(_model.AutoHideMinHeight) : new GridLength(_model.AutoHideHeight, GridUnitType.Pixel), - }); + } + else if( _side == AnchorSide.Bottom ) + { + _internalGrid.RowDefinitions.Add( new RowDefinition() { Height = new GridLength( _manager.GridSplitterHeight ) } ); + _internalGrid.RowDefinitions.Add( new RowDefinition() + { + Height = _model.AutoHideHeight == 0.0 ? new GridLength( _model.AutoHideMinHeight ) : new GridLength( _model.AutoHideHeight, GridUnitType.Pixel ), + } ); - Grid.SetRow(_resizer, 0); - Grid.SetRow(_internalHost, 1); + Grid.SetRow( _resizer, 0 ); + Grid.SetRow( _internalHost, 1 ); - _resizer.Cursor = Cursors.SizeNS; + _resizer.Cursor = Cursors.SizeNS; - VerticalAlignment = System.Windows.VerticalAlignment.Bottom; - HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch; - } + VerticalAlignment = System.Windows.VerticalAlignment.Bottom; + HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch; + } - _internalGrid.Children.Add(_resizer); - _internalGrid.Children.Add(_internalHost); - _internalHostPresenter.Content = _internalGrid; - } + _internalGrid.Children.Add( _resizer ); + _internalGrid.Children.Add( _internalHost ); + _internalHostPresenter.Content = _internalGrid; + } - void RemoveInternalGrid() - { - _resizer.DragStarted -= new System.Windows.Controls.Primitives.DragStartedEventHandler(OnResizerDragStarted); - _resizer.DragDelta -= new System.Windows.Controls.Primitives.DragDeltaEventHandler(OnResizerDragDelta); - _resizer.DragCompleted -= new System.Windows.Controls.Primitives.DragCompletedEventHandler(OnResizerDragCompleted); + void RemoveInternalGrid() + { + _resizer.DragStarted -= new System.Windows.Controls.Primitives.DragStartedEventHandler( OnResizerDragStarted ); + _resizer.DragDelta -= new System.Windows.Controls.Primitives.DragDeltaEventHandler( OnResizerDragDelta ); + _resizer.DragCompleted -= new System.Windows.Controls.Primitives.DragCompletedEventHandler( OnResizerDragCompleted ); - _internalHostPresenter.Content = null; - } + _internalHostPresenter.Content = null; + } - protected override bool HasFocusWithinCore() - { - return false; - } + protected override bool HasFocusWithinCore() + { + return false; + } - #region Resizer + #region Resizer - Border _resizerGhost = null; - Window _resizerWindowHost = null; - Vector _initialStartPoint; + Border _resizerGhost = null; + Window _resizerWindowHost = null; + Vector _initialStartPoint; - void ShowResizerOverlayWindow(LayoutGridResizerControl splitter) - { - _resizerGhost = new Border() - { - Background = splitter.BackgroundWhileDragging, - Opacity = splitter.OpacityWhileDragging - }; - - var areaElement = _manager.GetAutoHideAreaElement(); - var modelControlActualSize = this._internalHost.TransformActualSizeToAncestor(); - - Point ptTopLeftScreen = areaElement.PointToScreenDPIWithoutFlowDirection(new Point()); - - var managerSize = areaElement.TransformActualSizeToAncestor(); - - Size windowSize; - - if (_side == AnchorSide.Right || _side == AnchorSide.Left) - { - windowSize = new Size( - managerSize.Width - 25.0 + splitter.ActualWidth, - managerSize.Height); - - _resizerGhost.Width = splitter.ActualWidth; - _resizerGhost.Height = windowSize.Height; - ptTopLeftScreen.Offset(25, 0.0); - } - else - { - windowSize = new Size( - managerSize.Width, - managerSize.Height - _model.AutoHideMinHeight - 25.0 + splitter.ActualHeight); - - _resizerGhost.Height = splitter.ActualHeight; - _resizerGhost.Width = windowSize.Width; - ptTopLeftScreen.Offset(0.0, 25.0); - } - - _initialStartPoint = splitter.PointToScreenDPIWithoutFlowDirection(new Point()) - ptTopLeftScreen; - - if (_side == AnchorSide.Right || _side == AnchorSide.Left) - { - Canvas.SetLeft(_resizerGhost, _initialStartPoint.X); - } - else - { - Canvas.SetTop(_resizerGhost, _initialStartPoint.Y); - } - - Canvas panelHostResizer = new Canvas() - { - HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch, - VerticalAlignment = System.Windows.VerticalAlignment.Stretch - }; - - panelHostResizer.Children.Add(_resizerGhost); - - - _resizerWindowHost = new Window() - { - ResizeMode = ResizeMode.NoResize, - WindowStyle = System.Windows.WindowStyle.None, - ShowInTaskbar = false, - AllowsTransparency = true, - Background = null, - Width = windowSize.Width, - Height = windowSize.Height, - Left = ptTopLeftScreen.X, - Top = ptTopLeftScreen.Y, - ShowActivated = false, - Owner = Window.GetWindow(this), - Content = panelHostResizer - }; - - _resizerWindowHost.Show(); - } + void ShowResizerOverlayWindow( LayoutGridResizerControl splitter ) + { + _resizerGhost = new Border() + { + Background = splitter.BackgroundWhileDragging, + Opacity = splitter.OpacityWhileDragging + }; + + var areaElement = _manager.GetAutoHideAreaElement(); + var modelControlActualSize = this._internalHost.TransformActualSizeToAncestor(); + + Point ptTopLeftScreen = areaElement.PointToScreenDPIWithoutFlowDirection( new Point() ); + + var managerSize = areaElement.TransformActualSizeToAncestor(); + + Size windowSize; + + if( _side == AnchorSide.Right || _side == AnchorSide.Left ) + { + windowSize = new Size( + managerSize.Width - 25.0 + splitter.ActualWidth, + managerSize.Height ); + + _resizerGhost.Width = splitter.ActualWidth; + _resizerGhost.Height = windowSize.Height; + ptTopLeftScreen.Offset( 25, 0.0 ); + } + else + { + windowSize = new Size( + managerSize.Width, + managerSize.Height - _model.AutoHideMinHeight - 25.0 + splitter.ActualHeight ); + + _resizerGhost.Height = splitter.ActualHeight; + _resizerGhost.Width = windowSize.Width; + ptTopLeftScreen.Offset( 0.0, 25.0 ); + } + + _initialStartPoint = splitter.PointToScreenDPIWithoutFlowDirection( new Point() ) - ptTopLeftScreen; + + if( _side == AnchorSide.Right || _side == AnchorSide.Left ) + { + Canvas.SetLeft( _resizerGhost, _initialStartPoint.X ); + } + else + { + Canvas.SetTop( _resizerGhost, _initialStartPoint.Y ); + } + + Canvas panelHostResizer = new Canvas() + { + HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch, + VerticalAlignment = System.Windows.VerticalAlignment.Stretch + }; + + panelHostResizer.Children.Add( _resizerGhost ); + + + _resizerWindowHost = new Window() + { + ResizeMode = ResizeMode.NoResize, + WindowStyle = System.Windows.WindowStyle.None, + ShowInTaskbar = false, + AllowsTransparency = true, + Background = null, + Width = windowSize.Width, + Height = windowSize.Height, + Left = ptTopLeftScreen.X, + Top = ptTopLeftScreen.Y, + ShowActivated = false, + Owner = Window.GetWindow( this ), + Content = panelHostResizer + }; + + _resizerWindowHost.Show(); + } - void HideResizerOverlayWindow() - { - if (_resizerWindowHost != null) - { - _resizerWindowHost.Close(); - _resizerWindowHost = null; - } - } + void HideResizerOverlayWindow() + { + if( _resizerWindowHost != null ) + { + _resizerWindowHost.Close(); + _resizerWindowHost = null; + } + } - internal bool IsResizing - { - get; - private set; - } + internal bool IsResizing + { + get; + private set; + } - void OnResizerDragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e) - { - LayoutGridResizerControl splitter = sender as LayoutGridResizerControl; - var rootVisual = this.FindVisualTreeRoot() as Visual; - - var trToWnd = TransformToAncestor(rootVisual); - Vector transformedDelta = trToWnd.Transform(new Point(e.HorizontalChange, e.VerticalChange)) - - trToWnd.Transform(new Point()); - - double delta; - if (_side == AnchorSide.Right || _side == AnchorSide.Left) - delta = Canvas.GetLeft(_resizerGhost) - _initialStartPoint.X; - else - delta = Canvas.GetTop(_resizerGhost) - _initialStartPoint.Y; - - if (_side == AnchorSide.Right) - { - if (_model.AutoHideWidth == 0.0) - _model.AutoHideWidth = _internalHost.ActualWidth - delta; - else - _model.AutoHideWidth -= delta; - - _internalGrid.ColumnDefinitions[1].Width = new GridLength(_model.AutoHideWidth, GridUnitType.Pixel); - } - else if (_side == AnchorSide.Left) - { - if (_model.AutoHideWidth == 0.0) - _model.AutoHideWidth = _internalHost.ActualWidth + delta; - else - _model.AutoHideWidth += delta; - - _internalGrid.ColumnDefinitions[0].Width = new GridLength(_model.AutoHideWidth, GridUnitType.Pixel); - } - else if (_side == AnchorSide.Top) - { - if (_model.AutoHideHeight == 0.0) - _model.AutoHideHeight = _internalHost.ActualHeight + delta; - else - _model.AutoHideHeight += delta; - - _internalGrid.RowDefinitions[0].Height = new GridLength(_model.AutoHideHeight, GridUnitType.Pixel); - } - else if (_side == AnchorSide.Bottom) - { - if (_model.AutoHideHeight == 0.0) - _model.AutoHideHeight = _internalHost.ActualHeight - delta; - else - _model.AutoHideHeight -= delta; - - _internalGrid.RowDefinitions[1].Height = new GridLength(_model.AutoHideHeight, GridUnitType.Pixel); - } - - HideResizerOverlayWindow(); - - IsResizing = false; - InvalidateMeasure(); - } + void OnResizerDragCompleted( object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e ) + { + LayoutGridResizerControl splitter = sender as LayoutGridResizerControl; + var rootVisual = this.FindVisualTreeRoot() as Visual; + + var trToWnd = TransformToAncestor( rootVisual ); + Vector transformedDelta = trToWnd.Transform( new Point( e.HorizontalChange, e.VerticalChange ) ) - + trToWnd.Transform( new Point() ); + + double delta; + if( _side == AnchorSide.Right || _side == AnchorSide.Left ) + delta = Canvas.GetLeft( _resizerGhost ) - _initialStartPoint.X; + else + delta = Canvas.GetTop( _resizerGhost ) - _initialStartPoint.Y; + + if( _side == AnchorSide.Right ) + { + if( _model.AutoHideWidth == 0.0 ) + _model.AutoHideWidth = _internalHost.ActualWidth - delta; + else + _model.AutoHideWidth -= delta; + + _internalGrid.ColumnDefinitions[ 1 ].Width = new GridLength( _model.AutoHideWidth, GridUnitType.Pixel ); + } + else if( _side == AnchorSide.Left ) + { + if( _model.AutoHideWidth == 0.0 ) + _model.AutoHideWidth = _internalHost.ActualWidth + delta; + else + _model.AutoHideWidth += delta; + + _internalGrid.ColumnDefinitions[ 0 ].Width = new GridLength( _model.AutoHideWidth, GridUnitType.Pixel ); + } + else if( _side == AnchorSide.Top ) + { + if( _model.AutoHideHeight == 0.0 ) + _model.AutoHideHeight = _internalHost.ActualHeight + delta; + else + _model.AutoHideHeight += delta; + + _internalGrid.RowDefinitions[ 0 ].Height = new GridLength( _model.AutoHideHeight, GridUnitType.Pixel ); + } + else if( _side == AnchorSide.Bottom ) + { + if( _model.AutoHideHeight == 0.0 ) + _model.AutoHideHeight = _internalHost.ActualHeight - delta; + else + _model.AutoHideHeight -= delta; + + _internalGrid.RowDefinitions[ 1 ].Height = new GridLength( _model.AutoHideHeight, GridUnitType.Pixel ); + } + + HideResizerOverlayWindow(); + + IsResizing = false; + InvalidateMeasure(); + } - void OnResizerDragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e) - { - LayoutGridResizerControl splitter = sender as LayoutGridResizerControl; - var rootVisual = this.FindVisualTreeRoot() as Visual; - - var trToWnd = TransformToAncestor(rootVisual); - Vector transformedDelta = trToWnd.Transform(new Point(e.HorizontalChange, e.VerticalChange)) - - trToWnd.Transform(new Point()); - - if (_side == AnchorSide.Right || _side == AnchorSide.Left) - { - if (FrameworkElement.GetFlowDirection(_internalHost) == System.Windows.FlowDirection.RightToLeft) - transformedDelta.X = -transformedDelta.X; - Canvas.SetLeft(_resizerGhost, MathHelper.MinMax(_initialStartPoint.X + transformedDelta.X, 0.0, _resizerWindowHost.Width - _resizerGhost.Width)); - } - else - { - Canvas.SetTop(_resizerGhost, MathHelper.MinMax(_initialStartPoint.Y + transformedDelta.Y, 0.0, _resizerWindowHost.Height - _resizerGhost.Height)); - } - } + void OnResizerDragDelta( object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e ) + { + LayoutGridResizerControl splitter = sender as LayoutGridResizerControl; + var rootVisual = this.FindVisualTreeRoot() as Visual; + + var trToWnd = TransformToAncestor( rootVisual ); + Vector transformedDelta = trToWnd.Transform( new Point( e.HorizontalChange, e.VerticalChange ) ) - + trToWnd.Transform( new Point() ); + + if( _side == AnchorSide.Right || _side == AnchorSide.Left ) + { + if( FrameworkElement.GetFlowDirection( _internalHost ) == System.Windows.FlowDirection.RightToLeft ) + transformedDelta.X = -transformedDelta.X; + Canvas.SetLeft( _resizerGhost, MathHelper.MinMax( _initialStartPoint.X + transformedDelta.X, 0.0, _resizerWindowHost.Width - _resizerGhost.Width ) ); + } + else + { + Canvas.SetTop( _resizerGhost, MathHelper.MinMax( _initialStartPoint.Y + transformedDelta.Y, 0.0, _resizerWindowHost.Height - _resizerGhost.Height ) ); + } + } - void OnResizerDragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e) - { - var resizer = sender as LayoutGridResizerControl; - ShowResizerOverlayWindow(resizer); - IsResizing = true; - } - #endregion + void OnResizerDragStarted( object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e ) + { + var resizer = sender as LayoutGridResizerControl; + ShowResizerOverlayWindow( resizer ); + IsResizing = true; + } + #endregion - protected override System.Collections.IEnumerator LogicalChildren - { - get - { - if (_internalHostPresenter == null) - return new UIElement[] { }.GetEnumerator(); - return new UIElement[] { _internalHostPresenter }.GetEnumerator(); - } - } + protected override System.Collections.IEnumerator LogicalChildren + { + get + { + if( _internalHostPresenter == null ) + return new UIElement[] { }.GetEnumerator(); + return new UIElement[] { _internalHostPresenter }.GetEnumerator(); + } + } - protected override Size MeasureOverride(Size constraint) - { - if (_internalHostPresenter == null) - return base.MeasureOverride(constraint); + protected override Size MeasureOverride( Size constraint ) + { + if( _internalHostPresenter == null ) + return base.MeasureOverride( constraint ); - _internalHostPresenter.Measure(constraint); - //return base.MeasureOverride(constraint); - return _internalHostPresenter.DesiredSize; - } + _internalHostPresenter.Measure( constraint ); + //return base.MeasureOverride(constraint); + return _internalHostPresenter.DesiredSize; + } - protected override Size ArrangeOverride(Size finalSize) - { - if (_internalHostPresenter == null) - return base.ArrangeOverride(finalSize); + protected override Size ArrangeOverride( Size finalSize ) + { + if( _internalHostPresenter == null ) + return base.ArrangeOverride( finalSize ); - _internalHostPresenter.Arrange(new Rect(finalSize)); - return base.ArrangeOverride(finalSize);// new Size(_internalHostPresenter.ActualWidth, _internalHostPresenter.ActualHeight); - } + _internalHostPresenter.Arrange( new Rect( finalSize ) ); + return base.ArrangeOverride( finalSize );// new Size(_internalHostPresenter.ActualWidth, _internalHostPresenter.ActualHeight); + } - #region Background + #region Background - /// - /// Background Dependency Property - /// - public static readonly DependencyProperty BackgroundProperty = - DependencyProperty.Register("Background", typeof(Brush), typeof(LayoutAutoHideWindowControl), - new FrameworkPropertyMetadata((Brush)null)); + /// + /// Background Dependency Property + /// + public static readonly DependencyProperty BackgroundProperty = + DependencyProperty.Register( "Background", typeof( Brush ), typeof( LayoutAutoHideWindowControl ), + new FrameworkPropertyMetadata( ( Brush )null ) ); - /// - /// Gets or sets the Background property. This dependency property - /// indicates background of the autohide childwindow. - /// - public Brush Background - { - get { return (Brush)GetValue(BackgroundProperty); } - set { SetValue(BackgroundProperty, value); } - } + /// + /// Gets or sets the Background property. This dependency property + /// indicates background of the autohide childwindow. + /// + public Brush Background + { + get + { + return ( Brush )GetValue( BackgroundProperty ); + } + set + { + SetValue( BackgroundProperty, value ); + } + } - #endregion + #endregion - internal bool IsWin32MouseOver - { - get - { - var ptMouse = new Win32Helper.Win32Point(); - if (!Win32Helper.GetCursorPos(ref ptMouse)) - return false; + internal bool IsWin32MouseOver + { + get + { + var ptMouse = new Win32Helper.Win32Point(); + if( !Win32Helper.GetCursorPos( ref ptMouse ) ) + return false; - Point location = this.PointToScreenDPI(new Point()); + Point location = this.PointToScreenDPI( new Point() ); - Rect rectWindow = this.GetScreenArea(); - if (rectWindow.Contains(new Point(ptMouse.X, ptMouse.Y))) - return true; + Rect rectWindow = this.GetScreenArea(); + if( rectWindow.Contains( new Point( ptMouse.X, ptMouse.Y ) ) ) + return true; - var manager = Model.Root.Manager; - var anchor = manager.FindVisualChildren().Where(c => c.Model == Model).FirstOrDefault(); + var manager = Model.Root.Manager; + var anchor = manager.FindVisualChildren().Where( c => c.Model == Model ).FirstOrDefault(); - if (anchor == null) - return false; + if( anchor == null ) + return false; - location = anchor.PointToScreenDPI(new Point()); + location = anchor.PointToScreenDPI( new Point() ); - if (anchor.IsMouseOver) - return true; + if( anchor.IsMouseOver ) + return true; - return false; - } - } + return false; + } + } - #region AnchorableStyle + #region AnchorableStyle - /// - /// AnchorableStyle Dependency Property - /// - public static readonly DependencyProperty AnchorableStyleProperty = - DependencyProperty.Register("AnchorableStyle", typeof(Style), typeof(LayoutAutoHideWindowControl), - new FrameworkPropertyMetadata((Style)null)); + /// + /// AnchorableStyle Dependency Property + /// + public static readonly DependencyProperty AnchorableStyleProperty = + DependencyProperty.Register( "AnchorableStyle", typeof( Style ), typeof( LayoutAutoHideWindowControl ), + new FrameworkPropertyMetadata( ( Style )null ) ); - /// - /// Gets or sets the AnchorableStyle property. This dependency property - /// indicates the style to apply to the LayoutAnchorableControl hosted in this auto hide window. - /// - public Style AnchorableStyle - { - get { return (Style)GetValue(AnchorableStyleProperty); } - set { SetValue(AnchorableStyleProperty, value); } - } + /// + /// Gets or sets the AnchorableStyle property. This dependency property + /// indicates the style to apply to the LayoutAnchorableControl hosted in this auto hide window. + /// + public Style AnchorableStyle + { + get + { + return ( Style )GetValue( AnchorableStyleProperty ); + } + set + { + SetValue( AnchorableStyleProperty, value ); + } + } - #endregion + #endregion - } + } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentControl.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentControl.cs index d7edb46a..3baf8548 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentControl.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentControl.cs @@ -160,6 +160,7 @@ namespace Xceed.Wpf.AvalonDock.Controls base.OnMouseLeftButtonDown( e ); } + private void SetIsActive() { if( this.Model != null ) diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentPaneControl.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentPaneControl.cs index c9d049fe..d7371e3c 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentPaneControl.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutDocumentPaneControl.cs @@ -16,83 +16,84 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Windows; -using System.Collections.ObjectModel; using System.Windows.Controls; using System.Windows.Data; using Xceed.Wpf.AvalonDock.Layout; namespace Xceed.Wpf.AvalonDock.Controls { - public class LayoutDocumentPaneControl : TabControl, ILayoutControl//, ILogicalChildrenContainer + public class LayoutDocumentPaneControl : TabControl, ILayoutControl//, ILogicalChildrenContainer + { + static LayoutDocumentPaneControl() { - static LayoutDocumentPaneControl() - { - FocusableProperty.OverrideMetadata(typeof(LayoutDocumentPaneControl), new FrameworkPropertyMetadata(false)); - } + FocusableProperty.OverrideMetadata( typeof( LayoutDocumentPaneControl ), new FrameworkPropertyMetadata( false ) ); + } - internal LayoutDocumentPaneControl(LayoutDocumentPane model) - { - if (model == null) - throw new ArgumentNullException("model"); + internal LayoutDocumentPaneControl( LayoutDocumentPane model ) + { + if( model == null ) + throw new ArgumentNullException( "model" ); - _model = model; - SetBinding(ItemsSourceProperty, new Binding("Model.Children") { Source = this }); - SetBinding(FlowDirectionProperty, new Binding("Model.Root.Manager.FlowDirection") { Source = this }); + _model = model; + SetBinding( ItemsSourceProperty, new Binding( "Model.Children" ) { Source = this } ); + SetBinding( FlowDirectionProperty, new Binding( "Model.Root.Manager.FlowDirection" ) { Source = this } ); - this.LayoutUpdated += new EventHandler(OnLayoutUpdated); - } + this.LayoutUpdated += new EventHandler( OnLayoutUpdated ); + } - void OnLayoutUpdated(object sender, EventArgs e) - { - var modelWithAtcualSize = _model as ILayoutPositionableElementWithActualSize; - modelWithAtcualSize.ActualWidth = ActualWidth; - modelWithAtcualSize.ActualHeight = ActualHeight; - } + void OnLayoutUpdated( object sender, EventArgs e ) + { + var modelWithAtcualSize = _model as ILayoutPositionableElementWithActualSize; + modelWithAtcualSize.ActualWidth = ActualWidth; + modelWithAtcualSize.ActualHeight = ActualHeight; + } - protected override void OnSelectionChanged(SelectionChangedEventArgs e) - { - base.OnSelectionChanged(e); + protected override void OnSelectionChanged( SelectionChangedEventArgs e ) + { + base.OnSelectionChanged( e ); - if (_model.SelectedContent != null) - _model.SelectedContent.IsActive = true; - } + if( _model.SelectedContent != null ) + _model.SelectedContent.IsActive = true; + } - List _logicalChildren = new List(); + List _logicalChildren = new List(); - protected override System.Collections.IEnumerator LogicalChildren - { - get - { - return _logicalChildren.GetEnumerator(); - } - } + protected override System.Collections.IEnumerator LogicalChildren + { + get + { + return _logicalChildren.GetEnumerator(); + } + } - LayoutDocumentPane _model; + LayoutDocumentPane _model; - public ILayoutElement Model - { - get { return _model; } - } + public ILayoutElement Model + { + get + { + return _model; + } + } - protected override void OnMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e) - { - base.OnMouseLeftButtonDown(e); + protected override void OnMouseLeftButtonDown( System.Windows.Input.MouseButtonEventArgs e ) + { + base.OnMouseLeftButtonDown( e ); - if (!e.Handled && _model.SelectedContent != null) - _model.SelectedContent.IsActive = true; - } + if( !e.Handled && _model.SelectedContent != null ) + _model.SelectedContent.IsActive = true; + } - protected override void OnMouseRightButtonDown(System.Windows.Input.MouseButtonEventArgs e) - { - base.OnMouseRightButtonDown(e); + protected override void OnMouseRightButtonDown( System.Windows.Input.MouseButtonEventArgs e ) + { + base.OnMouseRightButtonDown( e ); - if (!e.Handled && _model.SelectedContent != null) - _model.SelectedContent.IsActive = true; + if( !e.Handled && _model.SelectedContent != null ) + _model.SelectedContent.IsActive = true; - } } + + } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutFloatingWindowControl.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutFloatingWindowControl.cs index d2cbe8b3..f8231f19 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutFloatingWindowControl.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutFloatingWindowControl.cs @@ -15,9 +15,7 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; using System.Linq; -using System.Text; using System.Windows; using System.Runtime.InteropServices; using System.Windows.Interop; @@ -26,10 +24,8 @@ using System.Windows.Controls; using System.Windows.Data; using System.Windows.Media; using Xceed.Wpf.AvalonDock.Layout; -using System.Diagnostics; using System.Windows.Documents; using Xceed.Wpf.AvalonDock.Themes; -using Microsoft.Windows.Shell; namespace Xceed.Wpf.AvalonDock.Controls { @@ -50,7 +46,7 @@ namespace Xceed.Wpf.AvalonDock.Controls return new FloatingWindowContentHost( sender as LayoutFloatingWindowControl ) { Content = content as UIElement }; } - protected class FloatingWindowContentHost : HwndHost + protected internal class FloatingWindowContentHost : HwndHost { LayoutFloatingWindowControl _owner; public FloatingWindowContentHost( LayoutFloatingWindowControl owner ) @@ -302,6 +298,7 @@ namespace Xceed.Wpf.AvalonDock.Controls base.OnInitialized( e ); } + public abstract ILayoutElement Model { get; diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutItem.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutItem.cs index 683c95af..a57f9c13 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutItem.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/LayoutItem.cs @@ -29,179 +29,180 @@ using System.Windows.Controls; namespace Xceed.Wpf.AvalonDock.Controls { - public abstract class LayoutItem : FrameworkElement + public abstract class LayoutItem : FrameworkElement + { + static LayoutItem() { - static LayoutItem() - { - ToolTipProperty.OverrideMetadata(typeof(LayoutItem), new FrameworkPropertyMetadata(null, (s, e) => OnToolTipChanged(s,e))); - VisibilityProperty.OverrideMetadata(typeof(LayoutItem), new FrameworkPropertyMetadata(Visibility.Visible, (s,e) => OnVisibilityChanged(s, e))); - } + ToolTipProperty.OverrideMetadata( typeof( LayoutItem ), new FrameworkPropertyMetadata( null, ( s, e ) => OnToolTipChanged( s, e ) ) ); + VisibilityProperty.OverrideMetadata( typeof( LayoutItem ), new FrameworkPropertyMetadata( Visibility.Visible, ( s, e ) => OnVisibilityChanged( s, e ) ) ); + } - internal LayoutItem() - { + internal LayoutItem() + { - } + } - internal virtual void Attach(LayoutContent model) - { - LayoutElement = model; - Model = model.Content; + internal virtual void Attach( LayoutContent model ) + { + LayoutElement = model; + Model = model.Content; - InitDefaultCommands(); + InitDefaultCommands(); - LayoutElement.IsSelectedChanged+=new EventHandler(LayoutElement_IsSelectedChanged); - LayoutElement.IsActiveChanged+=new EventHandler(LayoutElement_IsActiveChanged); + LayoutElement.IsSelectedChanged += new EventHandler( LayoutElement_IsSelectedChanged ); + LayoutElement.IsActiveChanged += new EventHandler( LayoutElement_IsActiveChanged ); - DataContext = this; - } + DataContext = this; + } - void LayoutElement_IsActiveChanged(object sender, EventArgs e) + void LayoutElement_IsActiveChanged( object sender, EventArgs e ) + { + if( _isActiveReentrantFlag.CanEnter ) + { + using( _isActiveReentrantFlag.Enter() ) { - if (_isActiveReentrantFlag.CanEnter) - { - using (_isActiveReentrantFlag.Enter()) - { - var bnd = BindingOperations.GetBinding(this, IsActiveProperty); - IsActive = LayoutElement.IsActive; - var bnd2 = BindingOperations.GetBinding(this, IsActiveProperty); - } - } + var bnd = BindingOperations.GetBinding( this, IsActiveProperty ); + IsActive = LayoutElement.IsActive; + var bnd2 = BindingOperations.GetBinding( this, IsActiveProperty ); } + } + } - void LayoutElement_IsSelectedChanged(object sender, EventArgs e) + void LayoutElement_IsSelectedChanged( object sender, EventArgs e ) + { + if( _isSelectedReentrantFlag.CanEnter ) + { + using( _isSelectedReentrantFlag.Enter() ) { - if (_isSelectedReentrantFlag.CanEnter) - { - using (_isSelectedReentrantFlag.Enter()) - { - IsSelected = LayoutElement.IsSelected; - } - } + IsSelected = LayoutElement.IsSelected; } + } + } - internal virtual void Detach() - { - LayoutElement.IsSelectedChanged -= new EventHandler(LayoutElement_IsSelectedChanged); - LayoutElement.IsActiveChanged -= new EventHandler(LayoutElement_IsActiveChanged); - LayoutElement = null; - Model = null; - } + internal virtual void Detach() + { + LayoutElement.IsSelectedChanged -= new EventHandler( LayoutElement_IsSelectedChanged ); + LayoutElement.IsActiveChanged -= new EventHandler( LayoutElement_IsActiveChanged ); + LayoutElement = null; + Model = null; + } - public LayoutContent LayoutElement - { - get; - private set; - } + public LayoutContent LayoutElement + { + get; + private set; + } - public object Model - { - get; - private set; - } + public object Model + { + get; + private set; + } - ICommand _defaultCloseCommand; - ICommand _defaultFloatCommand; - ICommand _defaultDockAsDocumentCommand; - ICommand _defaultCloseAllButThisCommand; - ICommand _defaultCloseAllCommand; - ICommand _defaultActivateCommand; - ICommand _defaultNewVerticalTabGroupCommand; - ICommand _defaultNewHorizontalTabGroupCommand; - ICommand _defaultMoveToNextTabGroupCommand; - ICommand _defaultMoveToPreviousTabGroupCommand; - - protected virtual void InitDefaultCommands() - { - _defaultCloseCommand = new RelayCommand((p) => ExecuteCloseCommand(p), (p) => CanExecuteCloseCommand(p)); - _defaultFloatCommand = new RelayCommand((p) => ExecuteFloatCommand(p), (p) => CanExecuteFloatCommand(p)); - _defaultDockAsDocumentCommand = new RelayCommand((p) => ExecuteDockAsDocumentCommand(p), (p) => CanExecuteDockAsDocumentCommand(p)); - _defaultCloseAllButThisCommand = new RelayCommand((p) => ExecuteCloseAllButThisCommand(p), (p) => CanExecuteCloseAllButThisCommand(p)); - _defaultCloseAllCommand = new RelayCommand( ( p ) => ExecuteCloseAllCommand( p ), ( p ) => CanExecuteCloseAllCommand( p ) ); - _defaultActivateCommand = new RelayCommand( ( p ) => ExecuteActivateCommand( p ), ( p ) => CanExecuteActivateCommand( p ) ); - _defaultNewVerticalTabGroupCommand = new RelayCommand((p) => ExecuteNewVerticalTabGroupCommand(p), (p) => CanExecuteNewVerticalTabGroupCommand(p)); - _defaultNewHorizontalTabGroupCommand = new RelayCommand((p) => ExecuteNewHorizontalTabGroupCommand(p), (p) => CanExecuteNewHorizontalTabGroupCommand(p)); - _defaultMoveToNextTabGroupCommand = new RelayCommand((p) => ExecuteMoveToNextTabGroupCommand(p), (p) => CanExecuteMoveToNextTabGroupCommand(p)); - _defaultMoveToPreviousTabGroupCommand = new RelayCommand((p) => ExecuteMoveToPreviousTabGroupCommand(p), (p) => CanExecuteMoveToPreviousTabGroupCommand(p)); - } + ICommand _defaultCloseCommand; + ICommand _defaultFloatCommand; + ICommand _defaultDockAsDocumentCommand; + ICommand _defaultCloseAllButThisCommand; + ICommand _defaultCloseAllCommand; + ICommand _defaultActivateCommand; + ICommand _defaultNewVerticalTabGroupCommand; + ICommand _defaultNewHorizontalTabGroupCommand; + ICommand _defaultMoveToNextTabGroupCommand; + ICommand _defaultMoveToPreviousTabGroupCommand; + + protected virtual void InitDefaultCommands() + { + _defaultCloseCommand = new RelayCommand( ( p ) => ExecuteCloseCommand( p ), ( p ) => CanExecuteCloseCommand( p ) ); + _defaultFloatCommand = new RelayCommand( ( p ) => ExecuteFloatCommand( p ), ( p ) => CanExecuteFloatCommand( p ) ); + _defaultDockAsDocumentCommand = new RelayCommand( ( p ) => ExecuteDockAsDocumentCommand( p ), ( p ) => CanExecuteDockAsDocumentCommand( p ) ); + _defaultCloseAllButThisCommand = new RelayCommand( ( p ) => ExecuteCloseAllButThisCommand( p ), ( p ) => CanExecuteCloseAllButThisCommand( p ) ); + _defaultCloseAllCommand = new RelayCommand( ( p ) => ExecuteCloseAllCommand( p ), ( p ) => CanExecuteCloseAllCommand( p ) ); + _defaultActivateCommand = new RelayCommand( ( p ) => ExecuteActivateCommand( p ), ( p ) => CanExecuteActivateCommand( p ) ); + _defaultNewVerticalTabGroupCommand = new RelayCommand( ( p ) => ExecuteNewVerticalTabGroupCommand( p ), ( p ) => CanExecuteNewVerticalTabGroupCommand( p ) ); + _defaultNewHorizontalTabGroupCommand = new RelayCommand( ( p ) => ExecuteNewHorizontalTabGroupCommand( p ), ( p ) => CanExecuteNewHorizontalTabGroupCommand( p ) ); + _defaultMoveToNextTabGroupCommand = new RelayCommand( ( p ) => ExecuteMoveToNextTabGroupCommand( p ), ( p ) => CanExecuteMoveToNextTabGroupCommand( p ) ); + _defaultMoveToPreviousTabGroupCommand = new RelayCommand( ( p ) => ExecuteMoveToPreviousTabGroupCommand( p ), ( p ) => CanExecuteMoveToPreviousTabGroupCommand( p ) ); + } - protected virtual void ClearDefaultBindings() - { - if (CloseCommand == _defaultCloseCommand) - BindingOperations.ClearBinding(this, CloseCommandProperty); - if (FloatCommand == _defaultFloatCommand) - BindingOperations.ClearBinding(this, FloatCommandProperty); - if (DockAsDocumentCommand == _defaultDockAsDocumentCommand) - BindingOperations.ClearBinding(this, DockAsDocumentCommandProperty); - if (CloseAllButThisCommand == _defaultCloseAllButThisCommand) - BindingOperations.ClearBinding(this, CloseAllButThisCommandProperty); - if( CloseAllCommand == _defaultCloseAllCommand ) - BindingOperations.ClearBinding( this, CloseAllCommandProperty ); - if (ActivateCommand == _defaultActivateCommand) - BindingOperations.ClearBinding(this, ActivateCommandProperty); - if (NewVerticalTabGroupCommand == _defaultNewVerticalTabGroupCommand) - BindingOperations.ClearBinding(this, NewVerticalTabGroupCommandProperty); - if (NewHorizontalTabGroupCommand == _defaultNewHorizontalTabGroupCommand) - BindingOperations.ClearBinding(this, NewHorizontalTabGroupCommandProperty); - if (MoveToNextTabGroupCommand == _defaultMoveToNextTabGroupCommand) - BindingOperations.ClearBinding(this, MoveToNextTabGroupCommandProperty); - if (MoveToPreviousTabGroupCommand == _defaultMoveToPreviousTabGroupCommand) - BindingOperations.ClearBinding(this, MoveToPreviousTabGroupCommandProperty); - } + protected virtual void ClearDefaultBindings() + { + if( CloseCommand == _defaultCloseCommand ) + BindingOperations.ClearBinding( this, CloseCommandProperty ); + if( FloatCommand == _defaultFloatCommand ) + BindingOperations.ClearBinding( this, FloatCommandProperty ); + if( DockAsDocumentCommand == _defaultDockAsDocumentCommand ) + BindingOperations.ClearBinding( this, DockAsDocumentCommandProperty ); + if( CloseAllButThisCommand == _defaultCloseAllButThisCommand ) + BindingOperations.ClearBinding( this, CloseAllButThisCommandProperty ); + if( CloseAllCommand == _defaultCloseAllCommand ) + BindingOperations.ClearBinding( this, CloseAllCommandProperty ); + if( ActivateCommand == _defaultActivateCommand ) + BindingOperations.ClearBinding( this, ActivateCommandProperty ); + if( NewVerticalTabGroupCommand == _defaultNewVerticalTabGroupCommand ) + BindingOperations.ClearBinding( this, NewVerticalTabGroupCommandProperty ); + if( NewHorizontalTabGroupCommand == _defaultNewHorizontalTabGroupCommand ) + BindingOperations.ClearBinding( this, NewHorizontalTabGroupCommandProperty ); + if( MoveToNextTabGroupCommand == _defaultMoveToNextTabGroupCommand ) + BindingOperations.ClearBinding( this, MoveToNextTabGroupCommandProperty ); + if( MoveToPreviousTabGroupCommand == _defaultMoveToPreviousTabGroupCommand ) + BindingOperations.ClearBinding( this, MoveToPreviousTabGroupCommandProperty ); + } - protected virtual void SetDefaultBindings() - { - if (CloseCommand == null) - CloseCommand = _defaultCloseCommand; - if (FloatCommand == null) - FloatCommand = _defaultFloatCommand; - if (DockAsDocumentCommand == null) - DockAsDocumentCommand = _defaultDockAsDocumentCommand; - if (CloseAllButThisCommand == null) - CloseAllButThisCommand = _defaultCloseAllButThisCommand; - if( CloseAllCommand == null ) - CloseAllCommand = _defaultCloseAllCommand; - if (ActivateCommand == null) - ActivateCommand = _defaultActivateCommand; - if (NewVerticalTabGroupCommand == null) - NewVerticalTabGroupCommand = _defaultNewVerticalTabGroupCommand; - if (NewHorizontalTabGroupCommand == null) - NewHorizontalTabGroupCommand = _defaultNewHorizontalTabGroupCommand; - if (MoveToNextTabGroupCommand == null) - MoveToNextTabGroupCommand = _defaultMoveToNextTabGroupCommand; - if (MoveToPreviousTabGroupCommand == null) - MoveToPreviousTabGroupCommand = _defaultMoveToPreviousTabGroupCommand; - - - IsSelected = LayoutElement.IsSelected; - IsActive = LayoutElement.IsActive; - } + protected virtual void SetDefaultBindings() + { + if( CloseCommand == null ) + CloseCommand = _defaultCloseCommand; + if( FloatCommand == null ) + FloatCommand = _defaultFloatCommand; + if( DockAsDocumentCommand == null ) + DockAsDocumentCommand = _defaultDockAsDocumentCommand; + if( CloseAllButThisCommand == null ) + CloseAllButThisCommand = _defaultCloseAllButThisCommand; + if( CloseAllCommand == null ) + CloseAllCommand = _defaultCloseAllCommand; + if( ActivateCommand == null ) + ActivateCommand = _defaultActivateCommand; + if( NewVerticalTabGroupCommand == null ) + NewVerticalTabGroupCommand = _defaultNewVerticalTabGroupCommand; + if( NewHorizontalTabGroupCommand == null ) + NewHorizontalTabGroupCommand = _defaultNewHorizontalTabGroupCommand; + if( MoveToNextTabGroupCommand == null ) + MoveToNextTabGroupCommand = _defaultMoveToNextTabGroupCommand; + if( MoveToPreviousTabGroupCommand == null ) + MoveToPreviousTabGroupCommand = _defaultMoveToPreviousTabGroupCommand; + + + IsSelected = LayoutElement.IsSelected; + IsActive = LayoutElement.IsActive; + CanClose = LayoutElement.CanClose; + } - internal void _ClearDefaultBindings() - { - ClearDefaultBindings(); - } + internal void _ClearDefaultBindings() + { + ClearDefaultBindings(); + } - internal void _SetDefaultBindings() - { - SetDefaultBindings(); - } + internal void _SetDefaultBindings() + { + SetDefaultBindings(); + } - internal bool IsViewExists() - { - return (_view != null); - } + internal bool IsViewExists() + { + return ( _view != null ); + } - ContentPresenter _view = null; - public ContentPresenter View + ContentPresenter _view = null; + public ContentPresenter View + { + get + { + if( _view == null ) { - get - { - if (_view == null) - { - _view = new ContentPresenter(); + _view = new ContentPresenter(); _view.SetBinding( ContentPresenter.ContentProperty, new Binding( "Content" ) { Source = LayoutElement } ); if( ( LayoutElement != null ) && ( LayoutElement.Root != null ) ) @@ -215,960 +216,1056 @@ namespace Xceed.Wpf.AvalonDock.Controls } } - return _view; - } - } + return _view; + } + } - #region Title + #region Title - /// - /// Title Dependency Property - /// - public static readonly DependencyProperty TitleProperty = - DependencyProperty.Register("Title", typeof(string), typeof(LayoutItem), - new FrameworkPropertyMetadata((string)null, - new PropertyChangedCallback(OnTitleChanged))); + /// + /// Title Dependency Property + /// + public static readonly DependencyProperty TitleProperty = + DependencyProperty.Register( "Title", typeof( string ), typeof( LayoutItem ), + new FrameworkPropertyMetadata( ( string )null, + new PropertyChangedCallback( OnTitleChanged ) ) ); - /// - /// Gets or sets the Title property. This dependency property - /// indicates the title of the element. - /// - public string Title - { - get { return (string)GetValue(TitleProperty); } - set { SetValue(TitleProperty, value); } - } + /// + /// Gets or sets the Title property. This dependency property + /// indicates the title of the element. + /// + public string Title + { + get + { + return ( string )GetValue( TitleProperty ); + } + set + { + SetValue( TitleProperty, value ); + } + } - /// - /// Handles changes to the Title property. - /// - private static void OnTitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((LayoutItem)d).OnTitleChanged(e); - } + /// + /// Handles changes to the Title property. + /// + private static void OnTitleChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )d ).OnTitleChanged( e ); + } - /// - /// Provides derived classes an opportunity to handle changes to the Title property. - /// - protected virtual void OnTitleChanged(DependencyPropertyChangedEventArgs e) - { - if (LayoutElement != null) - LayoutElement.Title = (string)e.NewValue; - } + /// + /// Provides derived classes an opportunity to handle changes to the Title property. + /// + protected virtual void OnTitleChanged( DependencyPropertyChangedEventArgs e ) + { + if( LayoutElement != null ) + LayoutElement.Title = ( string )e.NewValue; + } - #endregion + #endregion - #region ToolTip - private static void OnToolTipChanged(DependencyObject s, DependencyPropertyChangedEventArgs e) - { - ((LayoutItem)s).OnToolTipChanged(); - } + #region ToolTip + private static void OnToolTipChanged( DependencyObject s, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )s ).OnToolTipChanged(); + } - private void OnToolTipChanged() - { - if (LayoutElement != null) - LayoutElement.ToolTip = ToolTip; - } - #endregion - - #region IconSource - - /// - /// IconSource Dependency Property - /// - public static readonly DependencyProperty IconSourceProperty = - DependencyProperty.Register("IconSource", typeof(ImageSource), typeof(LayoutItem), - new FrameworkPropertyMetadata((ImageSource)null, - new PropertyChangedCallback(OnIconSourceChanged))); - - /// - /// Gets or sets the IconSource property. This dependency property - /// indicates icon associated with the item. - /// - public ImageSource IconSource - { - get { return (ImageSource)GetValue(IconSourceProperty); } - set { SetValue(IconSourceProperty, value); } - } + private void OnToolTipChanged() + { + if( LayoutElement != null ) + LayoutElement.ToolTip = ToolTip; + } + #endregion + + #region IconSource + + /// + /// IconSource Dependency Property + /// + public static readonly DependencyProperty IconSourceProperty = + DependencyProperty.Register( "IconSource", typeof( ImageSource ), typeof( LayoutItem ), + new FrameworkPropertyMetadata( ( ImageSource )null, + new PropertyChangedCallback( OnIconSourceChanged ) ) ); + + /// + /// Gets or sets the IconSource property. This dependency property + /// indicates icon associated with the item. + /// + public ImageSource IconSource + { + get + { + return ( ImageSource )GetValue( IconSourceProperty ); + } + set + { + SetValue( IconSourceProperty, value ); + } + } - /// - /// Handles changes to the IconSource property. - /// - private static void OnIconSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((LayoutItem)d).OnIconSourceChanged(e); - } + /// + /// Handles changes to the IconSource property. + /// + private static void OnIconSourceChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )d ).OnIconSourceChanged( e ); + } - /// - /// Provides derived classes an opportunity to handle changes to the IconSource property. - /// - protected virtual void OnIconSourceChanged(DependencyPropertyChangedEventArgs e) - { - if (LayoutElement != null) - LayoutElement.IconSource = IconSource; - } + /// + /// Provides derived classes an opportunity to handle changes to the IconSource property. + /// + protected virtual void OnIconSourceChanged( DependencyPropertyChangedEventArgs e ) + { + if( LayoutElement != null ) + LayoutElement.IconSource = IconSource; + } - #endregion + #endregion - #region Visibility + #region Visibility - private static void OnVisibilityChanged(DependencyObject s, DependencyPropertyChangedEventArgs e) - { - ((LayoutItem)s).OnVisibilityChanged(); - } + private static void OnVisibilityChanged( DependencyObject s, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )s ).OnVisibilityChanged(); + } - protected virtual void OnVisibilityChanged() - { - if (LayoutElement != null && - Visibility == System.Windows.Visibility.Collapsed) - LayoutElement.Close(); - } + protected virtual void OnVisibilityChanged() + { + if( LayoutElement != null && + Visibility == System.Windows.Visibility.Collapsed ) + LayoutElement.Close(); + } - #endregion + #endregion - #region ContentId + #region ContentId - /// - /// ContentId Dependency Property - /// - public static readonly DependencyProperty ContentIdProperty = - DependencyProperty.Register("ContentId", typeof(string), typeof(LayoutItem), - new FrameworkPropertyMetadata((string)null, - new PropertyChangedCallback(OnContentIdChanged))); + /// + /// ContentId Dependency Property + /// + public static readonly DependencyProperty ContentIdProperty = + DependencyProperty.Register( "ContentId", typeof( string ), typeof( LayoutItem ), + new FrameworkPropertyMetadata( ( string )null, + new PropertyChangedCallback( OnContentIdChanged ) ) ); - /// - /// Gets or sets the ContentId property. This dependency property - /// indicates the content id used to retrive content when deserializing layouts. - /// - public string ContentId - { - get { return (string)GetValue(ContentIdProperty); } - set { SetValue(ContentIdProperty, value); } - } + /// + /// Gets or sets the ContentId property. This dependency property + /// indicates the content id used to retrive content when deserializing layouts. + /// + public string ContentId + { + get + { + return ( string )GetValue( ContentIdProperty ); + } + set + { + SetValue( ContentIdProperty, value ); + } + } - /// - /// Handles changes to the ContentId property. - /// - private static void OnContentIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((LayoutItem)d).OnContentIdChanged(e); - } + /// + /// Handles changes to the ContentId property. + /// + private static void OnContentIdChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )d ).OnContentIdChanged( e ); + } - /// - /// Provides derived classes an opportunity to handle changes to the ContentId property. - /// - protected virtual void OnContentIdChanged(DependencyPropertyChangedEventArgs e) - { - if (LayoutElement != null) - LayoutElement.ContentId = (string)e.NewValue; - } + /// + /// Provides derived classes an opportunity to handle changes to the ContentId property. + /// + protected virtual void OnContentIdChanged( DependencyPropertyChangedEventArgs e ) + { + if( LayoutElement != null ) + LayoutElement.ContentId = ( string )e.NewValue; + } - #endregion + #endregion - #region IsSelected + #region IsSelected - ReentrantFlag _isSelectedReentrantFlag = new ReentrantFlag(); + ReentrantFlag _isSelectedReentrantFlag = new ReentrantFlag(); - /// - /// IsSelected Dependency Property - /// - public static readonly DependencyProperty IsSelectedProperty = - DependencyProperty.Register("IsSelected", typeof(bool), typeof(LayoutItem), - new FrameworkPropertyMetadata((bool)false, - new PropertyChangedCallback(OnIsSelectedChanged))); + /// + /// IsSelected Dependency Property + /// + public static readonly DependencyProperty IsSelectedProperty = + DependencyProperty.Register( "IsSelected", typeof( bool ), typeof( LayoutItem ), + new FrameworkPropertyMetadata( ( bool )false, + new PropertyChangedCallback( OnIsSelectedChanged ) ) ); - /// - /// Gets or sets the IsSelected property. This dependency property - /// indicates if the item is selected inside its container. - /// - public bool IsSelected - { - get { return (bool)GetValue(IsSelectedProperty); } - set { SetValue(IsSelectedProperty, value); } - } + /// + /// Gets or sets the IsSelected property. This dependency property + /// indicates if the item is selected inside its container. + /// + public bool IsSelected + { + get + { + return ( bool )GetValue( IsSelectedProperty ); + } + set + { + SetValue( IsSelectedProperty, value ); + } + } - /// - /// Handles changes to the IsSelected property. - /// - private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((LayoutItem)d).OnIsSelectedChanged(e); - } + /// + /// Handles changes to the IsSelected property. + /// + private static void OnIsSelectedChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )d ).OnIsSelectedChanged( e ); + } - /// - /// Provides derived classes an opportunity to handle changes to the IsSelected property. - /// - protected virtual void OnIsSelectedChanged(DependencyPropertyChangedEventArgs e) + /// + /// Provides derived classes an opportunity to handle changes to the IsSelected property. + /// + protected virtual void OnIsSelectedChanged( DependencyPropertyChangedEventArgs e ) + { + if( _isSelectedReentrantFlag.CanEnter ) + { + using( _isSelectedReentrantFlag.Enter() ) { - if (_isSelectedReentrantFlag.CanEnter) - { - using (_isSelectedReentrantFlag.Enter()) - { - if (LayoutElement != null) - LayoutElement.IsSelected = (bool)e.NewValue; - } - } + if( LayoutElement != null ) + LayoutElement.IsSelected = ( bool )e.NewValue; } + } + } - #endregion + #endregion - #region IsActive + #region IsActive - ReentrantFlag _isActiveReentrantFlag = new ReentrantFlag(); + ReentrantFlag _isActiveReentrantFlag = new ReentrantFlag(); - /// - /// IsActive Dependency Property - /// - public static readonly DependencyProperty IsActiveProperty = - DependencyProperty.Register("IsActive", typeof(bool), typeof(LayoutItem), - new FrameworkPropertyMetadata((bool)false, - new PropertyChangedCallback(OnIsActiveChanged))); + /// + /// IsActive Dependency Property + /// + public static readonly DependencyProperty IsActiveProperty = + DependencyProperty.Register( "IsActive", typeof( bool ), typeof( LayoutItem ), + new FrameworkPropertyMetadata( ( bool )false, + new PropertyChangedCallback( OnIsActiveChanged ) ) ); - /// - /// Gets or sets the IsActive property. This dependency property - /// indicates if the item is active in the UI. - /// - public bool IsActive - { - get { return (bool)GetValue(IsActiveProperty); } - set { SetValue(IsActiveProperty, value); } - } + /// + /// Gets or sets the IsActive property. This dependency property + /// indicates if the item is active in the UI. + /// + public bool IsActive + { + get + { + return ( bool )GetValue( IsActiveProperty ); + } + set + { + SetValue( IsActiveProperty, value ); + } + } - /// - /// Handles changes to the IsActive property. - /// - private static void OnIsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((LayoutItem)d).OnIsActiveChanged(e); - } + /// + /// Handles changes to the IsActive property. + /// + private static void OnIsActiveChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )d ).OnIsActiveChanged( e ); + } - /// - /// Provides derived classes an opportunity to handle changes to the IsActive property. - /// - protected virtual void OnIsActiveChanged(DependencyPropertyChangedEventArgs e) + /// + /// Provides derived classes an opportunity to handle changes to the IsActive property. + /// + protected virtual void OnIsActiveChanged( DependencyPropertyChangedEventArgs e ) + { + if( _isActiveReentrantFlag.CanEnter ) + { + using( _isActiveReentrantFlag.Enter() ) { - if (_isActiveReentrantFlag.CanEnter) - { - using (_isActiveReentrantFlag.Enter()) - { - if (LayoutElement != null) - LayoutElement.IsActive = (bool)e.NewValue; - } - } + if( LayoutElement != null ) + LayoutElement.IsActive = ( bool )e.NewValue; } + } + } - #endregion - - #region CanClose + #endregion - /// - /// CanClose Dependency Property - /// - public static readonly DependencyProperty CanCloseProperty = - DependencyProperty.Register("CanClose", typeof(bool), typeof(LayoutItem), - new FrameworkPropertyMetadata((bool)true, - new PropertyChangedCallback(OnCanCloseChanged))); + #region CanClose - /// - /// Gets or sets the CanClose property. This dependency property - /// indicates if the item can be closed. - /// - public bool CanClose - { - get { return (bool)GetValue(CanCloseProperty); } - set { SetValue(CanCloseProperty, value); } - } + /// + /// CanClose Dependency Property + /// + public static readonly DependencyProperty CanCloseProperty = + DependencyProperty.Register( "CanClose", typeof( bool ), typeof( LayoutItem ), + new FrameworkPropertyMetadata( ( bool )true, + new PropertyChangedCallback( OnCanCloseChanged ) ) ); - /// - /// Handles changes to the CanClose property. - /// - private static void OnCanCloseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((LayoutItem)d).OnCanCloseChanged(e); - } + /// + /// Gets or sets the CanClose property. This dependency property + /// indicates if the item can be closed. + /// + public bool CanClose + { + get + { + return ( bool )GetValue( CanCloseProperty ); + } + set + { + SetValue( CanCloseProperty, value ); + } + } - /// - /// Provides derived classes an opportunity to handle changes to the CanClose property. - /// - protected virtual void OnCanCloseChanged(DependencyPropertyChangedEventArgs e) - { - if (LayoutElement != null) - LayoutElement.CanClose = (bool)e.NewValue; - } + /// + /// Handles changes to the CanClose property. + /// + private static void OnCanCloseChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )d ).OnCanCloseChanged( e ); + } - #endregion + /// + /// Provides derived classes an opportunity to handle changes to the CanClose property. + /// + protected virtual void OnCanCloseChanged( DependencyPropertyChangedEventArgs e ) + { + if( LayoutElement != null ) + LayoutElement.CanClose = ( bool )e.NewValue; + } - #region CanFloat + #endregion - /// - /// CanFloat Dependency Property - /// - public static readonly DependencyProperty CanFloatProperty = - DependencyProperty.Register("CanFloat", typeof(bool), typeof(LayoutItem), - new FrameworkPropertyMetadata((bool)true, - new PropertyChangedCallback(OnCanFloatChanged))); + #region CanFloat - /// - /// Gets or sets the CanFloat property. This dependency property - /// indicates if user can move the layout element dragging it to another position. - /// - public bool CanFloat - { - get { return (bool)GetValue(CanFloatProperty); } - set { SetValue(CanFloatProperty, value); } - } + /// + /// CanFloat Dependency Property + /// + public static readonly DependencyProperty CanFloatProperty = + DependencyProperty.Register( "CanFloat", typeof( bool ), typeof( LayoutItem ), + new FrameworkPropertyMetadata( ( bool )true, + new PropertyChangedCallback( OnCanFloatChanged ) ) ); - /// - /// Handles changes to the CanFloat property. - /// - private static void OnCanFloatChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((LayoutItem)d).OnCanFloatChanged(e); - } + /// + /// Gets or sets the CanFloat property. This dependency property + /// indicates if user can move the layout element dragging it to another position. + /// + public bool CanFloat + { + get + { + return ( bool )GetValue( CanFloatProperty ); + } + set + { + SetValue( CanFloatProperty, value ); + } + } - /// - /// Provides derived classes an opportunity to handle changes to the CanFloat property. - /// - protected virtual void OnCanFloatChanged(DependencyPropertyChangedEventArgs e) - { - if (LayoutElement != null) - LayoutElement.CanFloat = (bool)e.NewValue; - } + /// + /// Handles changes to the CanFloat property. + /// + private static void OnCanFloatChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )d ).OnCanFloatChanged( e ); + } - #endregion + /// + /// Provides derived classes an opportunity to handle changes to the CanFloat property. + /// + protected virtual void OnCanFloatChanged( DependencyPropertyChangedEventArgs e ) + { + if( LayoutElement != null ) + LayoutElement.CanFloat = ( bool )e.NewValue; + } - #region CloseCommand + #endregion - /// - /// CloseCommand Dependency Property - /// - public static readonly DependencyProperty CloseCommandProperty = - DependencyProperty.Register("CloseCommand", typeof(ICommand), typeof(LayoutItem), - new FrameworkPropertyMetadata(null, - new PropertyChangedCallback(OnCloseCommandChanged), - new CoerceValueCallback(CoerceCloseCommandValue))); + #region CloseCommand - /// - /// Gets or sets the CloseCommand property. This dependency property - /// indicates the command to execute when user click the document close button. - /// - public ICommand CloseCommand - { - get { return (ICommand)GetValue(CloseCommandProperty); } - set { SetValue(CloseCommandProperty, value); } - } + /// + /// CloseCommand Dependency Property + /// + public static readonly DependencyProperty CloseCommandProperty = + DependencyProperty.Register( "CloseCommand", typeof( ICommand ), typeof( LayoutItem ), + new FrameworkPropertyMetadata( null, + new PropertyChangedCallback( OnCloseCommandChanged ), + new CoerceValueCallback( CoerceCloseCommandValue ) ) ); - /// - /// Handles changes to the CloseCommand property. - /// - private static void OnCloseCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((LayoutItem)d).OnCloseCommandChanged(e); - } - - /// - /// Provides derived classes an opportunity to handle changes to the CloseCommand property. - /// - protected virtual void OnCloseCommandChanged(DependencyPropertyChangedEventArgs e) - { - } + /// + /// Gets or sets the CloseCommand property. This dependency property + /// indicates the command to execute when user click the document close button. + /// + public ICommand CloseCommand + { + get + { + return ( ICommand )GetValue( CloseCommandProperty ); + } + set + { + SetValue( CloseCommandProperty, value ); + } + } - /// - /// Coerces the CloseCommand value. - /// - private static object CoerceCloseCommandValue(DependencyObject d, object value) - { - return value; - } + /// + /// Handles changes to the CloseCommand property. + /// + private static void OnCloseCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )d ).OnCloseCommandChanged( e ); + } - private bool CanExecuteCloseCommand(object parameter) - { - return LayoutElement != null && LayoutElement.CanClose; - } + /// + /// Provides derived classes an opportunity to handle changes to the CloseCommand property. + /// + protected virtual void OnCloseCommandChanged( DependencyPropertyChangedEventArgs e ) + { + } - private void ExecuteCloseCommand(object parameter) - { - Close(); - } + /// + /// Coerces the CloseCommand value. + /// + private static object CoerceCloseCommandValue( DependencyObject d, object value ) + { + return value; + } - protected abstract void Close(); + private bool CanExecuteCloseCommand( object parameter ) + { + return LayoutElement != null && LayoutElement.CanClose; + } + private void ExecuteCloseCommand( object parameter ) + { + Close(); + } - #endregion + protected abstract void Close(); - #region FloatCommand - /// - /// FloatCommand Dependency Property - /// - public static readonly DependencyProperty FloatCommandProperty = - DependencyProperty.Register("FloatCommand", typeof(ICommand), typeof(LayoutItem), - new FrameworkPropertyMetadata(null, - new PropertyChangedCallback(OnFloatCommandChanged), - new CoerceValueCallback(CoerceFloatCommandValue))); - /// - /// Gets or sets the FloatCommand property. This dependency property - /// indicates the command to execute when user click the float button. - /// - /// By default this command move the anchorable inside new floating window. - public ICommand FloatCommand - { - get { return (ICommand)GetValue(FloatCommandProperty); } - set { SetValue(FloatCommandProperty, value); } - } + #endregion - /// - /// Handles changes to the FloatCommand property. - /// - private static void OnFloatCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((LayoutItem)d).OnFloatCommandChanged(e); - } + #region FloatCommand + /// + /// FloatCommand Dependency Property + /// + public static readonly DependencyProperty FloatCommandProperty = + DependencyProperty.Register( "FloatCommand", typeof( ICommand ), typeof( LayoutItem ), + new FrameworkPropertyMetadata( null, + new PropertyChangedCallback( OnFloatCommandChanged ), + new CoerceValueCallback( CoerceFloatCommandValue ) ) ); - /// - /// Provides derived classes an opportunity to handle changes to the FloatCommand property. - /// - protected virtual void OnFloatCommandChanged(DependencyPropertyChangedEventArgs e) - { - } + /// + /// Gets or sets the FloatCommand property. This dependency property + /// indicates the command to execute when user click the float button. + /// + /// By default this command move the anchorable inside new floating window. + public ICommand FloatCommand + { + get + { + return ( ICommand )GetValue( FloatCommandProperty ); + } + set + { + SetValue( FloatCommandProperty, value ); + } + } - /// - /// Coerces the FloatCommand value. - /// - private static object CoerceFloatCommandValue(DependencyObject d, object value) - { - return value; - } + /// + /// Handles changes to the FloatCommand property. + /// + private static void OnFloatCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )d ).OnFloatCommandChanged( e ); + } - private bool CanExecuteFloatCommand(object anchorable) - { - return LayoutElement != null && LayoutElement.CanFloat && LayoutElement.FindParent() == null; - } + /// + /// Provides derived classes an opportunity to handle changes to the FloatCommand property. + /// + protected virtual void OnFloatCommandChanged( DependencyPropertyChangedEventArgs e ) + { + } - private void ExecuteFloatCommand(object parameter) - { - LayoutElement.Root.Manager._ExecuteFloatCommand(LayoutElement); - } + /// + /// Coerces the FloatCommand value. + /// + private static object CoerceFloatCommandValue( DependencyObject d, object value ) + { + return value; + } - protected virtual void Float() - { + private bool CanExecuteFloatCommand( object anchorable ) + { + return LayoutElement != null && LayoutElement.CanFloat && LayoutElement.FindParent() == null; + } - } + private void ExecuteFloatCommand( object parameter ) + { + LayoutElement.Root.Manager._ExecuteFloatCommand( LayoutElement ); + } - #endregion - - #region DockAsDocumentCommand - - /// - /// DockAsDocumentCommand Dependency Property - /// - public static readonly DependencyProperty DockAsDocumentCommandProperty = - DependencyProperty.Register("DockAsDocumentCommand", typeof(ICommand), typeof(LayoutItem), - new FrameworkPropertyMetadata(null, - new PropertyChangedCallback(OnDockAsDocumentCommandChanged), - new CoerceValueCallback(CoerceDockAsDocumentCommandValue))); - - /// - /// Gets or sets the DockAsDocumentCommand property. This dependency property - /// indicates the command to execute when user click the DockAsDocument button. - /// - /// By default this command move the anchorable inside the last focused document pane. - public ICommand DockAsDocumentCommand - { - get { return (ICommand)GetValue(DockAsDocumentCommandProperty); } - set { SetValue(DockAsDocumentCommandProperty, value); } - } + protected virtual void Float() + { - /// - /// Handles changes to the DockAsDocumentCommand property. - /// - private static void OnDockAsDocumentCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((LayoutItem)d).OnDockAsDocumentCommandChanged(e); - } + } - /// - /// Provides derived classes an opportunity to handle changes to the DockAsDocumentCommand property. - /// - protected virtual void OnDockAsDocumentCommandChanged(DependencyPropertyChangedEventArgs e) - { - } + #endregion + + #region DockAsDocumentCommand + + /// + /// DockAsDocumentCommand Dependency Property + /// + public static readonly DependencyProperty DockAsDocumentCommandProperty = + DependencyProperty.Register( "DockAsDocumentCommand", typeof( ICommand ), typeof( LayoutItem ), + new FrameworkPropertyMetadata( null, + new PropertyChangedCallback( OnDockAsDocumentCommandChanged ), + new CoerceValueCallback( CoerceDockAsDocumentCommandValue ) ) ); + + /// + /// Gets or sets the DockAsDocumentCommand property. This dependency property + /// indicates the command to execute when user click the DockAsDocument button. + /// + /// By default this command move the anchorable inside the last focused document pane. + public ICommand DockAsDocumentCommand + { + get + { + return ( ICommand )GetValue( DockAsDocumentCommandProperty ); + } + set + { + SetValue( DockAsDocumentCommandProperty, value ); + } + } - /// - /// Coerces the DockAsDocumentCommand value. - /// - private static object CoerceDockAsDocumentCommandValue(DependencyObject d, object value) - { - return value; - } + /// + /// Handles changes to the DockAsDocumentCommand property. + /// + private static void OnDockAsDocumentCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )d ).OnDockAsDocumentCommandChanged( e ); + } - private bool CanExecuteDockAsDocumentCommand(object parameter) - { - return LayoutElement != null && LayoutElement.FindParent() == null; - } + /// + /// Provides derived classes an opportunity to handle changes to the DockAsDocumentCommand property. + /// + protected virtual void OnDockAsDocumentCommandChanged( DependencyPropertyChangedEventArgs e ) + { + } - private void ExecuteDockAsDocumentCommand(object parameter) - { - LayoutElement.Root.Manager._ExecuteDockAsDocumentCommand(LayoutElement); - } + /// + /// Coerces the DockAsDocumentCommand value. + /// + private static object CoerceDockAsDocumentCommandValue( DependencyObject d, object value ) + { + return value; + } - #endregion + private bool CanExecuteDockAsDocumentCommand( object parameter ) + { + return LayoutElement != null && LayoutElement.FindParent() == null; + } - #region CloseAllButThisCommand + private void ExecuteDockAsDocumentCommand( object parameter ) + { + LayoutElement.Root.Manager._ExecuteDockAsDocumentCommand( LayoutElement ); + } - /// - /// CloseAllButThisCommand Dependency Property - /// - public static readonly DependencyProperty CloseAllButThisCommandProperty = - DependencyProperty.Register("CloseAllButThisCommand", typeof(ICommand), typeof(LayoutItem), - new FrameworkPropertyMetadata(null, - new PropertyChangedCallback(OnCloseAllButThisCommandChanged), - new CoerceValueCallback(CoerceCloseAllButThisCommandValue))); + #endregion - /// - /// Gets or sets the CloseAllButThisCommand property. This dependency property - /// indicates the 'Close All But This' command. - /// - public ICommand CloseAllButThisCommand - { - get { return (ICommand)GetValue(CloseAllButThisCommandProperty); } - set { SetValue(CloseAllButThisCommandProperty, value); } - } + #region CloseAllButThisCommand - /// - /// Handles changes to the CloseAllButThisCommand property. - /// - private static void OnCloseAllButThisCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((LayoutItem)d).OnCloseAllButThisCommandChanged(e); - } + /// + /// CloseAllButThisCommand Dependency Property + /// + public static readonly DependencyProperty CloseAllButThisCommandProperty = + DependencyProperty.Register( "CloseAllButThisCommand", typeof( ICommand ), typeof( LayoutItem ), + new FrameworkPropertyMetadata( null, + new PropertyChangedCallback( OnCloseAllButThisCommandChanged ), + new CoerceValueCallback( CoerceCloseAllButThisCommandValue ) ) ); - /// - /// Provides derived classes an opportunity to handle changes to the CloseAllButThisCommand property. - /// - protected virtual void OnCloseAllButThisCommandChanged(DependencyPropertyChangedEventArgs e) - { - } + /// + /// Gets or sets the CloseAllButThisCommand property. This dependency property + /// indicates the 'Close All But This' command. + /// + public ICommand CloseAllButThisCommand + { + get + { + return ( ICommand )GetValue( CloseAllButThisCommandProperty ); + } + set + { + SetValue( CloseAllButThisCommandProperty, value ); + } + } - /// - /// Coerces the CloseAllButThisCommand value. - /// - private static object CoerceCloseAllButThisCommandValue(DependencyObject d, object value) - { - return value; - } + /// + /// Handles changes to the CloseAllButThisCommand property. + /// + private static void OnCloseAllButThisCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )d ).OnCloseAllButThisCommandChanged( e ); + } - private bool CanExecuteCloseAllButThisCommand(object parameter) - { - if (LayoutElement == null) - return false; - var root = LayoutElement.Root; - if (root == null) - return false; - - return LayoutElement.Root.Manager.Layout. - Descendents().OfType().Where(d => d != LayoutElement && (d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow)).Any(); - } + /// + /// Provides derived classes an opportunity to handle changes to the CloseAllButThisCommand property. + /// + protected virtual void OnCloseAllButThisCommandChanged( DependencyPropertyChangedEventArgs e ) + { + } - private void ExecuteCloseAllButThisCommand(object parameter) - { - LayoutElement.Root.Manager._ExecuteCloseAllButThisCommand(LayoutElement); - } + /// + /// Coerces the CloseAllButThisCommand value. + /// + private static object CoerceCloseAllButThisCommandValue( DependencyObject d, object value ) + { + return value; + } - #endregion + private bool CanExecuteCloseAllButThisCommand( object parameter ) + { + if( LayoutElement == null ) + return false; + var root = LayoutElement.Root; + if( root == null ) + return false; + + return LayoutElement.Root.Manager.Layout. + Descendents().OfType().Where( d => d != LayoutElement && ( d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow ) ).Any(); + } - #region CloseAllCommand + private void ExecuteCloseAllButThisCommand( object parameter ) + { + LayoutElement.Root.Manager._ExecuteCloseAllButThisCommand( LayoutElement ); + } - /// - /// CloseAllCommand Dependency Property - /// - public static readonly DependencyProperty CloseAllCommandProperty = - DependencyProperty.Register( "CloseAllCommand", typeof( ICommand ), typeof( LayoutItem ), - new FrameworkPropertyMetadata( null, - new PropertyChangedCallback( OnCloseAllCommandChanged ), - new CoerceValueCallback( CoerceCloseAllCommandValue ) ) ); + #endregion - /// - /// Gets or sets the CloseAllCommand property. This dependency property - /// indicates the 'Close All' command. - /// - public ICommand CloseAllCommand - { - get - { - return ( ICommand )GetValue( CloseAllCommandProperty ); - } - set - { - SetValue( CloseAllCommandProperty, value ); - } - } + #region CloseAllCommand - /// - /// Handles changes to the CloseAllCommand property. - /// - private static void OnCloseAllCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) - { - ( ( LayoutItem )d ).OnCloseAllCommandChanged( e ); - } + /// + /// CloseAllCommand Dependency Property + /// + public static readonly DependencyProperty CloseAllCommandProperty = + DependencyProperty.Register( "CloseAllCommand", typeof( ICommand ), typeof( LayoutItem ), + new FrameworkPropertyMetadata( null, + new PropertyChangedCallback( OnCloseAllCommandChanged ), + new CoerceValueCallback( CoerceCloseAllCommandValue ) ) ); - /// - /// Provides derived classes an opportunity to handle changes to the CloseAllCommand property. - /// - protected virtual void OnCloseAllCommandChanged( DependencyPropertyChangedEventArgs e ) - { - } + /// + /// Gets or sets the CloseAllCommand property. This dependency property + /// indicates the 'Close All' command. + /// + public ICommand CloseAllCommand + { + get + { + return ( ICommand )GetValue( CloseAllCommandProperty ); + } + set + { + SetValue( CloseAllCommandProperty, value ); + } + } - /// - /// Coerces the CloseAllCommand value. - /// - private static object CoerceCloseAllCommandValue( DependencyObject d, object value ) - { - return value; - } + /// + /// Handles changes to the CloseAllCommand property. + /// + private static void OnCloseAllCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )d ).OnCloseAllCommandChanged( e ); + } - private bool CanExecuteCloseAllCommand( object parameter ) - { - if( LayoutElement == null ) - return false; - var root = LayoutElement.Root; - if( root == null ) - return false; - - return LayoutElement.Root.Manager.Layout. - Descendents().OfType().Where( d => ( d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow ) ).Any(); - } + /// + /// Provides derived classes an opportunity to handle changes to the CloseAllCommand property. + /// + protected virtual void OnCloseAllCommandChanged( DependencyPropertyChangedEventArgs e ) + { + } - private void ExecuteCloseAllCommand( object parameter ) - { - LayoutElement.Root.Manager._ExecuteCloseAllCommand( LayoutElement ); - } + /// + /// Coerces the CloseAllCommand value. + /// + private static object CoerceCloseAllCommandValue( DependencyObject d, object value ) + { + return value; + } - #endregion + private bool CanExecuteCloseAllCommand( object parameter ) + { + if( LayoutElement == null ) + return false; + var root = LayoutElement.Root; + if( root == null ) + return false; + + return LayoutElement.Root.Manager.Layout. + Descendents().OfType().Where( d => ( d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow ) ).Any(); + } - #region ActivateCommand + private void ExecuteCloseAllCommand( object parameter ) + { + LayoutElement.Root.Manager._ExecuteCloseAllCommand( LayoutElement ); + } - /// - /// ActivateCommand Dependency Property - /// - public static readonly DependencyProperty ActivateCommandProperty = - DependencyProperty.Register("ActivateCommand", typeof(ICommand), typeof(LayoutItem), - new FrameworkPropertyMetadata(null, - new PropertyChangedCallback(OnActivateCommandChanged), - new CoerceValueCallback(CoerceActivateCommandValue))); + #endregion - /// - /// Gets or sets the ActivateCommand property. This dependency property - /// indicates the command to execute when user wants to activate a content (either a Document or an Anchorable). - /// - public ICommand ActivateCommand - { - get { return (ICommand)GetValue(ActivateCommandProperty); } - set { SetValue(ActivateCommandProperty, value); } - } + #region ActivateCommand - /// - /// Handles changes to the ActivateCommand property. - /// - private static void OnActivateCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((LayoutItem)d).OnActivateCommandChanged(e); - } + /// + /// ActivateCommand Dependency Property + /// + public static readonly DependencyProperty ActivateCommandProperty = + DependencyProperty.Register( "ActivateCommand", typeof( ICommand ), typeof( LayoutItem ), + new FrameworkPropertyMetadata( null, + new PropertyChangedCallback( OnActivateCommandChanged ), + new CoerceValueCallback( CoerceActivateCommandValue ) ) ); - /// - /// Provides derived classes an opportunity to handle changes to the ActivateCommand property. - /// - protected virtual void OnActivateCommandChanged(DependencyPropertyChangedEventArgs e) - { - } + /// + /// Gets or sets the ActivateCommand property. This dependency property + /// indicates the command to execute when user wants to activate a content (either a Document or an Anchorable). + /// + public ICommand ActivateCommand + { + get + { + return ( ICommand )GetValue( ActivateCommandProperty ); + } + set + { + SetValue( ActivateCommandProperty, value ); + } + } - /// - /// Coerces the ActivateCommand value. - /// - private static object CoerceActivateCommandValue(DependencyObject d, object value) - { - return value; - } + /// + /// Handles changes to the ActivateCommand property. + /// + private static void OnActivateCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )d ).OnActivateCommandChanged( e ); + } - private bool CanExecuteActivateCommand(object parameter) - { - return LayoutElement != null; - } + /// + /// Provides derived classes an opportunity to handle changes to the ActivateCommand property. + /// + protected virtual void OnActivateCommandChanged( DependencyPropertyChangedEventArgs e ) + { + } - private void ExecuteActivateCommand(object parameter) - { - LayoutElement.Root.Manager._ExecuteContentActivateCommand(LayoutElement); - } + /// + /// Coerces the ActivateCommand value. + /// + private static object CoerceActivateCommandValue( DependencyObject d, object value ) + { + return value; + } - #endregion + private bool CanExecuteActivateCommand( object parameter ) + { + return LayoutElement != null; + } - #region NewVerticalTabGroupCommand + private void ExecuteActivateCommand( object parameter ) + { + LayoutElement.Root.Manager._ExecuteContentActivateCommand( LayoutElement ); + } - /// - /// NewVerticalTabGroupCommand Dependency Property - /// - public static readonly DependencyProperty NewVerticalTabGroupCommandProperty = - DependencyProperty.Register("NewVerticalTabGroupCommand", typeof(ICommand), typeof(LayoutItem), - new FrameworkPropertyMetadata((ICommand)null, - new PropertyChangedCallback(OnNewVerticalTabGroupCommandChanged))); + #endregion - /// - /// Gets or sets the NewVerticalTabGroupCommand property. This dependency property - /// indicates the new vertical tab group command. - /// - public ICommand NewVerticalTabGroupCommand - { - get { return (ICommand)GetValue(NewVerticalTabGroupCommandProperty); } - set { SetValue(NewVerticalTabGroupCommandProperty, value); } - } + #region NewVerticalTabGroupCommand - /// - /// Handles changes to the NewVerticalTabGroupCommand property. - /// - private static void OnNewVerticalTabGroupCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((LayoutItem)d).OnNewVerticalTabGroupCommandChanged(e); - } + /// + /// NewVerticalTabGroupCommand Dependency Property + /// + public static readonly DependencyProperty NewVerticalTabGroupCommandProperty = + DependencyProperty.Register( "NewVerticalTabGroupCommand", typeof( ICommand ), typeof( LayoutItem ), + new FrameworkPropertyMetadata( ( ICommand )null, + new PropertyChangedCallback( OnNewVerticalTabGroupCommandChanged ) ) ); - /// - /// Provides derived classes an opportunity to handle changes to the NewVerticalTabGroupCommand property. - /// - protected virtual void OnNewVerticalTabGroupCommandChanged(DependencyPropertyChangedEventArgs e) - { - } + /// + /// Gets or sets the NewVerticalTabGroupCommand property. This dependency property + /// indicates the new vertical tab group command. + /// + public ICommand NewVerticalTabGroupCommand + { + get + { + return ( ICommand )GetValue( NewVerticalTabGroupCommandProperty ); + } + set + { + SetValue( NewVerticalTabGroupCommandProperty, value ); + } + } - private bool CanExecuteNewVerticalTabGroupCommand(object parameter) - { - if (LayoutElement == null) - return false; - var parentDocumentGroup = LayoutElement.FindParent(); - var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane; - return ((parentDocumentGroup == null || - parentDocumentGroup.ChildrenCount == 1 || - parentDocumentGroup.Root.Manager.AllowMixedOrientation || - parentDocumentGroup.Orientation == System.Windows.Controls.Orientation.Horizontal) && - parentDocumentPane != null && - parentDocumentPane.ChildrenCount > 1); - } + /// + /// Handles changes to the NewVerticalTabGroupCommand property. + /// + private static void OnNewVerticalTabGroupCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )d ).OnNewVerticalTabGroupCommandChanged( e ); + } - private void ExecuteNewVerticalTabGroupCommand(object parameter) - { - var layoutElement = LayoutElement; - var parentDocumentGroup = layoutElement.FindParent(); - var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane; + /// + /// Provides derived classes an opportunity to handle changes to the NewVerticalTabGroupCommand property. + /// + protected virtual void OnNewVerticalTabGroupCommandChanged( DependencyPropertyChangedEventArgs e ) + { + } - if (parentDocumentGroup == null) - { - var grandParent = parentDocumentPane.Parent as ILayoutContainer; - parentDocumentGroup = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Horizontal }; - grandParent.ReplaceChild(parentDocumentPane, parentDocumentGroup); - parentDocumentGroup.Children.Add(parentDocumentPane); - } - parentDocumentGroup.Orientation = System.Windows.Controls.Orientation.Horizontal; - int indexOfParentPane = parentDocumentGroup.IndexOfChild(parentDocumentPane); - parentDocumentGroup.InsertChildAt(indexOfParentPane + 1, new LayoutDocumentPane(layoutElement)); - layoutElement.IsActive = true; - layoutElement.Root.CollectGarbage(); - } - #endregion - - #region NewHorizontalTabGroupCommand - - /// - /// NewHorizontalTabGroupCommand Dependency Property - /// - public static readonly DependencyProperty NewHorizontalTabGroupCommandProperty = - DependencyProperty.Register("NewHorizontalTabGroupCommand", typeof(ICommand), typeof(LayoutItem), - new FrameworkPropertyMetadata((ICommand)null, - new PropertyChangedCallback(OnNewHorizontalTabGroupCommandChanged))); - - /// - /// Gets or sets the NewHorizontalTabGroupCommand property. This dependency property - /// indicates the new horizontal tab group command. - /// - public ICommand NewHorizontalTabGroupCommand - { - get { return (ICommand)GetValue(NewHorizontalTabGroupCommandProperty); } - set { SetValue(NewHorizontalTabGroupCommandProperty, value); } - } + private bool CanExecuteNewVerticalTabGroupCommand( object parameter ) + { + if( LayoutElement == null ) + return false; + var parentDocumentGroup = LayoutElement.FindParent(); + var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane; + return ( ( parentDocumentGroup == null || + parentDocumentGroup.ChildrenCount == 1 || + parentDocumentGroup.Root.Manager.AllowMixedOrientation || + parentDocumentGroup.Orientation == System.Windows.Controls.Orientation.Horizontal ) && + parentDocumentPane != null && + parentDocumentPane.ChildrenCount > 1 ); + } - /// - /// Handles changes to the NewHorizontalTabGroupCommand property. - /// - private static void OnNewHorizontalTabGroupCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((LayoutItem)d).OnNewHorizontalTabGroupCommandChanged(e); - } + private void ExecuteNewVerticalTabGroupCommand( object parameter ) + { + var layoutElement = LayoutElement; + var parentDocumentGroup = layoutElement.FindParent(); + var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane; + + if( parentDocumentGroup == null ) + { + var grandParent = parentDocumentPane.Parent as ILayoutContainer; + parentDocumentGroup = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Horizontal }; + grandParent.ReplaceChild( parentDocumentPane, parentDocumentGroup ); + parentDocumentGroup.Children.Add( parentDocumentPane ); + } + parentDocumentGroup.Orientation = System.Windows.Controls.Orientation.Horizontal; + int indexOfParentPane = parentDocumentGroup.IndexOfChild( parentDocumentPane ); + parentDocumentGroup.InsertChildAt( indexOfParentPane + 1, new LayoutDocumentPane( layoutElement ) ); + layoutElement.IsActive = true; + layoutElement.Root.CollectGarbage(); + } + #endregion + + #region NewHorizontalTabGroupCommand + + /// + /// NewHorizontalTabGroupCommand Dependency Property + /// + public static readonly DependencyProperty NewHorizontalTabGroupCommandProperty = + DependencyProperty.Register( "NewHorizontalTabGroupCommand", typeof( ICommand ), typeof( LayoutItem ), + new FrameworkPropertyMetadata( ( ICommand )null, + new PropertyChangedCallback( OnNewHorizontalTabGroupCommandChanged ) ) ); + + /// + /// Gets or sets the NewHorizontalTabGroupCommand property. This dependency property + /// indicates the new horizontal tab group command. + /// + public ICommand NewHorizontalTabGroupCommand + { + get + { + return ( ICommand )GetValue( NewHorizontalTabGroupCommandProperty ); + } + set + { + SetValue( NewHorizontalTabGroupCommandProperty, value ); + } + } - /// - /// Provides derived classes an opportunity to handle changes to the NewHorizontalTabGroupCommand property. - /// - protected virtual void OnNewHorizontalTabGroupCommandChanged(DependencyPropertyChangedEventArgs e) - { - } + /// + /// Handles changes to the NewHorizontalTabGroupCommand property. + /// + private static void OnNewHorizontalTabGroupCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )d ).OnNewHorizontalTabGroupCommandChanged( e ); + } + /// + /// Provides derived classes an opportunity to handle changes to the NewHorizontalTabGroupCommand property. + /// + protected virtual void OnNewHorizontalTabGroupCommandChanged( DependencyPropertyChangedEventArgs e ) + { + } - private bool CanExecuteNewHorizontalTabGroupCommand(object parameter) - { - if (LayoutElement == null) - return false; - var parentDocumentGroup = LayoutElement.FindParent(); - var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane; - return ((parentDocumentGroup == null || - parentDocumentGroup.ChildrenCount == 1 || - parentDocumentGroup.Root.Manager.AllowMixedOrientation || - parentDocumentGroup.Orientation == System.Windows.Controls.Orientation.Vertical) && - parentDocumentPane != null && - parentDocumentPane.ChildrenCount > 1); - } - private void ExecuteNewHorizontalTabGroupCommand(object parameter) - { - var layoutElement = LayoutElement; - var parentDocumentGroup = layoutElement.FindParent(); - var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane; + private bool CanExecuteNewHorizontalTabGroupCommand( object parameter ) + { + if( LayoutElement == null ) + return false; + var parentDocumentGroup = LayoutElement.FindParent(); + var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane; + return ( ( parentDocumentGroup == null || + parentDocumentGroup.ChildrenCount == 1 || + parentDocumentGroup.Root.Manager.AllowMixedOrientation || + parentDocumentGroup.Orientation == System.Windows.Controls.Orientation.Vertical ) && + parentDocumentPane != null && + parentDocumentPane.ChildrenCount > 1 ); + } - if (parentDocumentGroup == null) - { - var grandParent = parentDocumentPane.Parent as ILayoutContainer; - parentDocumentGroup = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Vertical }; - grandParent.ReplaceChild(parentDocumentPane, parentDocumentGroup); - parentDocumentGroup.Children.Add(parentDocumentPane); - } - parentDocumentGroup.Orientation = System.Windows.Controls.Orientation.Vertical; - int indexOfParentPane = parentDocumentGroup.IndexOfChild(parentDocumentPane); - parentDocumentGroup.InsertChildAt(indexOfParentPane + 1, new LayoutDocumentPane(layoutElement)); - layoutElement.IsActive = true; - layoutElement.Root.CollectGarbage(); - } - #endregion - - #region MoveToNextTabGroupCommand - - /// - /// MoveToNextTabGroupCommand Dependency Property - /// - public static readonly DependencyProperty MoveToNextTabGroupCommandProperty = - DependencyProperty.Register("MoveToNextTabGroupCommand", typeof(ICommand), typeof(LayoutItem), - new FrameworkPropertyMetadata((ICommand)null, - new PropertyChangedCallback(OnMoveToNextTabGroupCommandChanged))); - - /// - /// Gets or sets the MoveToNextTabGroupCommand property. This dependency property - /// indicates move to next tab group command. - /// - public ICommand MoveToNextTabGroupCommand - { - get { return (ICommand)GetValue(MoveToNextTabGroupCommandProperty); } - set { SetValue(MoveToNextTabGroupCommandProperty, value); } - } + private void ExecuteNewHorizontalTabGroupCommand( object parameter ) + { + var layoutElement = LayoutElement; + var parentDocumentGroup = layoutElement.FindParent(); + var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane; + + if( parentDocumentGroup == null ) + { + var grandParent = parentDocumentPane.Parent as ILayoutContainer; + parentDocumentGroup = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Vertical }; + grandParent.ReplaceChild( parentDocumentPane, parentDocumentGroup ); + parentDocumentGroup.Children.Add( parentDocumentPane ); + } + parentDocumentGroup.Orientation = System.Windows.Controls.Orientation.Vertical; + int indexOfParentPane = parentDocumentGroup.IndexOfChild( parentDocumentPane ); + parentDocumentGroup.InsertChildAt( indexOfParentPane + 1, new LayoutDocumentPane( layoutElement ) ); + layoutElement.IsActive = true; + layoutElement.Root.CollectGarbage(); + } + #endregion + + #region MoveToNextTabGroupCommand + + /// + /// MoveToNextTabGroupCommand Dependency Property + /// + public static readonly DependencyProperty MoveToNextTabGroupCommandProperty = + DependencyProperty.Register( "MoveToNextTabGroupCommand", typeof( ICommand ), typeof( LayoutItem ), + new FrameworkPropertyMetadata( ( ICommand )null, + new PropertyChangedCallback( OnMoveToNextTabGroupCommandChanged ) ) ); + + /// + /// Gets or sets the MoveToNextTabGroupCommand property. This dependency property + /// indicates move to next tab group command. + /// + public ICommand MoveToNextTabGroupCommand + { + get + { + return ( ICommand )GetValue( MoveToNextTabGroupCommandProperty ); + } + set + { + SetValue( MoveToNextTabGroupCommandProperty, value ); + } + } - /// - /// Handles changes to the MoveToNextTabGroupCommand property. - /// - private static void OnMoveToNextTabGroupCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((LayoutItem)d).OnMoveToNextTabGroupCommandChanged(e); - } + /// + /// Handles changes to the MoveToNextTabGroupCommand property. + /// + private static void OnMoveToNextTabGroupCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )d ).OnMoveToNextTabGroupCommandChanged( e ); + } - /// - /// Provides derived classes an opportunity to handle changes to the MoveToNextTabGroupCommand property. - /// - protected virtual void OnMoveToNextTabGroupCommandChanged(DependencyPropertyChangedEventArgs e) - { - } + /// + /// Provides derived classes an opportunity to handle changes to the MoveToNextTabGroupCommand property. + /// + protected virtual void OnMoveToNextTabGroupCommandChanged( DependencyPropertyChangedEventArgs e ) + { + } - private bool CanExecuteMoveToNextTabGroupCommand(object parameter) - { - if (LayoutElement == null) - return false; - - var parentDocumentGroup = LayoutElement.FindParent(); - var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane; - return (parentDocumentGroup != null && - parentDocumentPane != null && - parentDocumentGroup.ChildrenCount > 1 && - parentDocumentGroup.IndexOfChild(parentDocumentPane) < parentDocumentGroup.ChildrenCount - 1 && - parentDocumentGroup.Children[parentDocumentGroup.IndexOfChild(parentDocumentPane) + 1] is LayoutDocumentPane); - } + private bool CanExecuteMoveToNextTabGroupCommand( object parameter ) + { + if( LayoutElement == null ) + return false; + + var parentDocumentGroup = LayoutElement.FindParent(); + var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane; + return ( parentDocumentGroup != null && + parentDocumentPane != null && + parentDocumentGroup.ChildrenCount > 1 && + parentDocumentGroup.IndexOfChild( parentDocumentPane ) < parentDocumentGroup.ChildrenCount - 1 && + parentDocumentGroup.Children[ parentDocumentGroup.IndexOfChild( parentDocumentPane ) + 1 ] is LayoutDocumentPane ); + } - private void ExecuteMoveToNextTabGroupCommand(object parameter) - { - var layoutElement = LayoutElement; - var parentDocumentGroup = layoutElement.FindParent(); - var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane; - int indexOfParentPane = parentDocumentGroup.IndexOfChild(parentDocumentPane); - var nextDocumentPane = parentDocumentGroup.Children[indexOfParentPane + 1] as LayoutDocumentPane; - nextDocumentPane.InsertChildAt(0, layoutElement); - layoutElement.IsActive = true; - layoutElement.Root.CollectGarbage(); - } + private void ExecuteMoveToNextTabGroupCommand( object parameter ) + { + var layoutElement = LayoutElement; + var parentDocumentGroup = layoutElement.FindParent(); + var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane; + int indexOfParentPane = parentDocumentGroup.IndexOfChild( parentDocumentPane ); + var nextDocumentPane = parentDocumentGroup.Children[ indexOfParentPane + 1 ] as LayoutDocumentPane; + nextDocumentPane.InsertChildAt( 0, layoutElement ); + layoutElement.IsActive = true; + layoutElement.Root.CollectGarbage(); + } - #endregion + #endregion - #region MoveToPreviousTabGroupCommand + #region MoveToPreviousTabGroupCommand - /// - /// MoveToPreviousTabGroupCommand Dependency Property - /// - public static readonly DependencyProperty MoveToPreviousTabGroupCommandProperty = - DependencyProperty.Register("MoveToPreviousTabGroupCommand", typeof(ICommand), typeof(LayoutItem), - new FrameworkPropertyMetadata((ICommand)null, - new PropertyChangedCallback(OnMoveToPreviousTabGroupCommandChanged))); + /// + /// MoveToPreviousTabGroupCommand Dependency Property + /// + public static readonly DependencyProperty MoveToPreviousTabGroupCommandProperty = + DependencyProperty.Register( "MoveToPreviousTabGroupCommand", typeof( ICommand ), typeof( LayoutItem ), + new FrameworkPropertyMetadata( ( ICommand )null, + new PropertyChangedCallback( OnMoveToPreviousTabGroupCommandChanged ) ) ); - /// - /// Gets or sets the MoveToPreviousTabGroupCommand property. This dependency property - /// indicates move to rpevious tab group command. - /// - public ICommand MoveToPreviousTabGroupCommand - { - get { return (ICommand)GetValue(MoveToPreviousTabGroupCommandProperty); } - set { SetValue(MoveToPreviousTabGroupCommandProperty, value); } - } + /// + /// Gets or sets the MoveToPreviousTabGroupCommand property. This dependency property + /// indicates move to rpevious tab group command. + /// + public ICommand MoveToPreviousTabGroupCommand + { + get + { + return ( ICommand )GetValue( MoveToPreviousTabGroupCommandProperty ); + } + set + { + SetValue( MoveToPreviousTabGroupCommandProperty, value ); + } + } - /// - /// Handles changes to the MoveToPreviousTabGroupCommand property. - /// - private static void OnMoveToPreviousTabGroupCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((LayoutItem)d).OnMoveToPreviousTabGroupCommandChanged(e); - } + /// + /// Handles changes to the MoveToPreviousTabGroupCommand property. + /// + private static void OnMoveToPreviousTabGroupCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( LayoutItem )d ).OnMoveToPreviousTabGroupCommandChanged( e ); + } - /// - /// Provides derived classes an opportunity to handle changes to the MoveToPreviousTabGroupCommand property. - /// - protected virtual void OnMoveToPreviousTabGroupCommandChanged(DependencyPropertyChangedEventArgs e) - { - } + /// + /// Provides derived classes an opportunity to handle changes to the MoveToPreviousTabGroupCommand property. + /// + protected virtual void OnMoveToPreviousTabGroupCommandChanged( DependencyPropertyChangedEventArgs e ) + { + } - private bool CanExecuteMoveToPreviousTabGroupCommand(object parameter) - { - if (LayoutElement == null) - return false; - var parentDocumentGroup = LayoutElement.FindParent(); - var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane; - return (parentDocumentGroup != null && - parentDocumentPane != null && - parentDocumentGroup.ChildrenCount > 1 && - parentDocumentGroup.IndexOfChild(parentDocumentPane) > 0 && - parentDocumentGroup.Children[parentDocumentGroup.IndexOfChild(parentDocumentPane) - 1] is LayoutDocumentPane); - } + private bool CanExecuteMoveToPreviousTabGroupCommand( object parameter ) + { + if( LayoutElement == null ) + return false; + var parentDocumentGroup = LayoutElement.FindParent(); + var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane; + return ( parentDocumentGroup != null && + parentDocumentPane != null && + parentDocumentGroup.ChildrenCount > 1 && + parentDocumentGroup.IndexOfChild( parentDocumentPane ) > 0 && + parentDocumentGroup.Children[ parentDocumentGroup.IndexOfChild( parentDocumentPane ) - 1 ] is LayoutDocumentPane ); + } - private void ExecuteMoveToPreviousTabGroupCommand(object parameter) - { - var layoutElement = LayoutElement; - var parentDocumentGroup = layoutElement.FindParent(); - var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane; - int indexOfParentPane = parentDocumentGroup.IndexOfChild(parentDocumentPane); - var nextDocumentPane = parentDocumentGroup.Children[indexOfParentPane - 1] as LayoutDocumentPane; - nextDocumentPane.InsertChildAt(0, layoutElement); - layoutElement.IsActive = true; - layoutElement.Root.CollectGarbage(); - } - #endregion + private void ExecuteMoveToPreviousTabGroupCommand( object parameter ) + { + var layoutElement = LayoutElement; + var parentDocumentGroup = layoutElement.FindParent(); + var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane; + int indexOfParentPane = parentDocumentGroup.IndexOfChild( parentDocumentPane ); + var nextDocumentPane = parentDocumentGroup.Children[ indexOfParentPane - 1 ] as LayoutDocumentPane; + nextDocumentPane.InsertChildAt( 0, layoutElement ); + layoutElement.IsActive = true; + layoutElement.Root.CollectGarbage(); + } + #endregion - } + } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/NavigatorWindow.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/NavigatorWindow.cs index 4f12a840..daf27ceb 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/NavigatorWindow.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Controls/NavigatorWindow.cs @@ -14,351 +14,366 @@ ***********************************************************************************/ -using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Windows; using Xceed.Wpf.AvalonDock.Layout; -using System.Windows.Interop; -using System.Windows.Threading; using Xceed.Wpf.AvalonDock.Themes; namespace Xceed.Wpf.AvalonDock.Controls { - public class NavigatorWindow : Window - { - private ResourceDictionary currentThemeResourceDictionary; // = null + public class NavigatorWindow : Window + { + private ResourceDictionary currentThemeResourceDictionary; // = null - static NavigatorWindow() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(NavigatorWindow), new FrameworkPropertyMetadata(typeof(NavigatorWindow))); - ShowActivatedProperty.OverrideMetadata(typeof(NavigatorWindow), new FrameworkPropertyMetadata(false)); - ShowInTaskbarProperty.OverrideMetadata(typeof(NavigatorWindow), new FrameworkPropertyMetadata(false)); - } + static NavigatorWindow() + { + DefaultStyleKeyProperty.OverrideMetadata( typeof( NavigatorWindow ), new FrameworkPropertyMetadata( typeof( NavigatorWindow ) ) ); + ShowActivatedProperty.OverrideMetadata( typeof( NavigatorWindow ), new FrameworkPropertyMetadata( false ) ); + ShowInTaskbarProperty.OverrideMetadata( typeof( NavigatorWindow ), new FrameworkPropertyMetadata( false ) ); + } - DockingManager _manager; - internal NavigatorWindow(DockingManager manager) - { - _manager = manager; + DockingManager _manager; + internal NavigatorWindow( DockingManager manager ) + { + _manager = manager; - _internalSetSelectedDocument = true; - SetAnchorables(_manager.Layout.Descendents().OfType().Where(a => a.IsVisible).Select(d => (LayoutAnchorableItem)_manager.GetLayoutItemFromModel(d)).ToArray()); - SetDocuments(_manager.Layout.Descendents().OfType().OrderByDescending(d => d.LastActivationTimeStamp.GetValueOrDefault()).Select(d => (LayoutDocumentItem)_manager.GetLayoutItemFromModel(d)).ToArray()); - _internalSetSelectedDocument = false; + _internalSetSelectedDocument = true; + SetAnchorables( _manager.Layout.Descendents().OfType().Where( a => a.IsVisible ).Select( d => ( LayoutAnchorableItem )_manager.GetLayoutItemFromModel( d ) ).ToArray() ); + SetDocuments( _manager.Layout.Descendents().OfType().OrderByDescending( d => d.LastActivationTimeStamp.GetValueOrDefault() ).Select( d => ( LayoutDocumentItem )_manager.GetLayoutItemFromModel( d ) ).ToArray() ); + _internalSetSelectedDocument = false; - if (Documents.Length > 1) - InternalSetSelectedDocument(Documents[1]); + if( Documents.Length > 1 ) + InternalSetSelectedDocument( Documents[ 1 ] ); - this.DataContext = this; + this.DataContext = this; - this.Loaded += new RoutedEventHandler(OnLoaded); - this.Unloaded += new RoutedEventHandler(OnUnloaded); + this.Loaded += new RoutedEventHandler( OnLoaded ); + this.Unloaded += new RoutedEventHandler( OnUnloaded ); - UpdateThemeResources(); - } + UpdateThemeResources(); + } - internal void UpdateThemeResources(Theme oldTheme = null) + internal void UpdateThemeResources( Theme oldTheme = null ) + { + if( oldTheme != null ) + { + if( oldTheme is DictionaryTheme ) { - if (oldTheme != null) - { - if( oldTheme is DictionaryTheme ) - { - if( currentThemeResourceDictionary != null ) - { - Resources.MergedDictionaries.Remove( currentThemeResourceDictionary ); - currentThemeResourceDictionary = null; - } - } - else - { - var resourceDictionaryToRemove = - Resources.MergedDictionaries.FirstOrDefault( r => r.Source == oldTheme.GetResourceUri() ); - if( resourceDictionaryToRemove != null ) - Resources.MergedDictionaries.Remove( - resourceDictionaryToRemove ); - } - } - - if (_manager.Theme != null) - { - if( _manager.Theme is DictionaryTheme ) - { - currentThemeResourceDictionary = ( ( DictionaryTheme )_manager.Theme ).ThemeResourceDictionary; - Resources.MergedDictionaries.Add( currentThemeResourceDictionary ); - } - else - { - Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = _manager.Theme.GetResourceUri() }); - } - } + if( currentThemeResourceDictionary != null ) + { + Resources.MergedDictionaries.Remove( currentThemeResourceDictionary ); + currentThemeResourceDictionary = null; + } } - - - void OnLoaded(object sender, RoutedEventArgs e) + else { - this.Loaded -= new RoutedEventHandler(OnLoaded); - - this.Focus(); - - //this.SetParentToMainWindowOf(_manager); - WindowStartupLocation = WindowStartupLocation.CenterOwner; + var resourceDictionaryToRemove = + Resources.MergedDictionaries.FirstOrDefault( r => r.Source == oldTheme.GetResourceUri() ); + if( resourceDictionaryToRemove != null ) + Resources.MergedDictionaries.Remove( + resourceDictionaryToRemove ); } + } - void OnUnloaded(object sender, RoutedEventArgs e) + if( _manager.Theme != null ) + { + if( _manager.Theme is DictionaryTheme ) { - this.Unloaded -= new RoutedEventHandler(OnUnloaded); - - //_hwndSrc.RemoveHook(_hwndSrcHook); - //_hwndSrc.Dispose(); - //_hwndSrc = null; + currentThemeResourceDictionary = ( ( DictionaryTheme )_manager.Theme ).ThemeResourceDictionary; + Resources.MergedDictionaries.Add( currentThemeResourceDictionary ); } - - //protected virtual IntPtr FilterMessage( - // IntPtr hwnd, - // int msg, - // IntPtr wParam, - // IntPtr lParam, - // ref bool handled - // ) - //{ - // handled = false; - - // switch (msg) - // { - // case Win32Helper.WM_ACTIVATE: - // if (((int)wParam & 0xFFFF) == Win32Helper.WA_INACTIVE) - // { - // if (lParam == new WindowInteropHelper(this.Owner).Handle) - // { - // Win32Helper.SetActiveWindow(_hwndSrc.Handle); - // handled = true; - // } - - // } - // break; - // } - - // return IntPtr.Zero; - //} - - - #region Documents - - /// - /// Documents Read-Only Dependency Property - /// - private static readonly DependencyPropertyKey DocumentsPropertyKey - = DependencyProperty.RegisterReadOnly("Documents", typeof(IEnumerable), typeof(NavigatorWindow), - new FrameworkPropertyMetadata(null)); - - public static readonly DependencyProperty DocumentsProperty - = DocumentsPropertyKey.DependencyProperty; - - /// - /// Gets the Documents property. This dependency property - /// indicates the list of documents. - /// - public LayoutDocumentItem[] Documents + else { - get { return (LayoutDocumentItem[])GetValue(DocumentsProperty); } + Resources.MergedDictionaries.Add( new ResourceDictionary() { Source = _manager.Theme.GetResourceUri() } ); } + } + } - /// - /// Provides a secure method for setting the Documents property. - /// This dependency property indicates the list of documents. - /// - /// The new value for the property. - protected void SetDocuments(LayoutDocumentItem[] value) - { - SetValue(DocumentsPropertyKey, value); - } - #endregion + void OnLoaded( object sender, RoutedEventArgs e ) + { + this.Loaded -= new RoutedEventHandler( OnLoaded ); - #region Anchorables + this.Focus(); - /// - /// Anchorables Read-Only Dependency Property - /// - private static readonly DependencyPropertyKey AnchorablesPropertyKey - = DependencyProperty.RegisterReadOnly("Anchorables", typeof(IEnumerable), typeof(NavigatorWindow), - new FrameworkPropertyMetadata((IEnumerable)null)); + //this.SetParentToMainWindowOf(_manager); + WindowStartupLocation = WindowStartupLocation.CenterOwner; + } - public static readonly DependencyProperty AnchorablesProperty - = AnchorablesPropertyKey.DependencyProperty; + void OnUnloaded( object sender, RoutedEventArgs e ) + { + this.Unloaded -= new RoutedEventHandler( OnUnloaded ); - /// - /// Gets the Anchorables property. This dependency property - /// indicates the list of anchorables. - /// - public IEnumerable Anchorables - { - get { return (IEnumerable)GetValue(AnchorablesProperty); } - } + //_hwndSrc.RemoveHook(_hwndSrcHook); + //_hwndSrc.Dispose(); + //_hwndSrc = null; + } - /// - /// Provides a secure method for setting the Anchorables property. - /// This dependency property indicates the list of anchorables. - /// - /// The new value for the property. - protected void SetAnchorables(IEnumerable value) - { - SetValue(AnchorablesPropertyKey, value); - } + //protected virtual IntPtr FilterMessage( + // IntPtr hwnd, + // int msg, + // IntPtr wParam, + // IntPtr lParam, + // ref bool handled + // ) + //{ + // handled = false; + + // switch (msg) + // { + // case Win32Helper.WM_ACTIVATE: + // if (((int)wParam & 0xFFFF) == Win32Helper.WA_INACTIVE) + // { + // if (lParam == new WindowInteropHelper(this.Owner).Handle) + // { + // Win32Helper.SetActiveWindow(_hwndSrc.Handle); + // handled = true; + // } + + // } + // break; + // } + + // return IntPtr.Zero; + //} + + + #region Documents + + /// + /// Documents Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey DocumentsPropertyKey + = DependencyProperty.RegisterReadOnly( "Documents", typeof( IEnumerable ), typeof( NavigatorWindow ), + new FrameworkPropertyMetadata( null ) ); + + public static readonly DependencyProperty DocumentsProperty + = DocumentsPropertyKey.DependencyProperty; + + /// + /// Gets the Documents property. This dependency property + /// indicates the list of documents. + /// + public LayoutDocumentItem[] Documents + { + get + { + return ( LayoutDocumentItem[] )GetValue( DocumentsProperty ); + } + } - #endregion + /// + /// Provides a secure method for setting the Documents property. + /// This dependency property indicates the list of documents. + /// + /// The new value for the property. + protected void SetDocuments( LayoutDocumentItem[] value ) + { + SetValue( DocumentsPropertyKey, value ); + } - #region SelectedDocument + #endregion - /// - /// SelectedDocument Dependency Property - /// - public static readonly DependencyProperty SelectedDocumentProperty = - DependencyProperty.Register("SelectedDocument", typeof(LayoutDocumentItem), typeof(NavigatorWindow), - new FrameworkPropertyMetadata((LayoutDocumentItem)null, - new PropertyChangedCallback(OnSelectedDocumentChanged))); + #region Anchorables - /// - /// Gets or sets the SelectedDocument property. This dependency property - /// indicates the selected document. - /// - public LayoutDocumentItem SelectedDocument - { - get { return (LayoutDocumentItem)GetValue(SelectedDocumentProperty); } - set { SetValue(SelectedDocumentProperty, value); } - } + /// + /// Anchorables Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey AnchorablesPropertyKey + = DependencyProperty.RegisterReadOnly( "Anchorables", typeof( IEnumerable ), typeof( NavigatorWindow ), + new FrameworkPropertyMetadata( ( IEnumerable )null ) ); - /// - /// Handles changes to the SelectedDocument property. - /// - private static void OnSelectedDocumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((NavigatorWindow)d).OnSelectedDocumentChanged(e); - } + public static readonly DependencyProperty AnchorablesProperty + = AnchorablesPropertyKey.DependencyProperty; - /// - /// Provides derived classes an opportunity to handle changes to the SelectedDocument property. - /// - protected virtual void OnSelectedDocumentChanged(DependencyPropertyChangedEventArgs e) - { - if (_internalSetSelectedDocument) - return; + /// + /// Gets the Anchorables property. This dependency property + /// indicates the list of anchorables. + /// + public IEnumerable Anchorables + { + get + { + return ( IEnumerable )GetValue( AnchorablesProperty ); + } + } - if (SelectedDocument != null && - SelectedDocument.ActivateCommand.CanExecute(null)) - { - SelectedDocument.ActivateCommand.Execute(null); - Hide(); - } + /// + /// Provides a secure method for setting the Anchorables property. + /// This dependency property indicates the list of anchorables. + /// + /// The new value for the property. + protected void SetAnchorables( IEnumerable value ) + { + SetValue( AnchorablesPropertyKey, value ); + } - } + #endregion - bool _internalSetSelectedDocument = false; - void InternalSetSelectedDocument(LayoutDocumentItem documentToSelect) - { - _internalSetSelectedDocument = true; - SelectedDocument = documentToSelect; - _internalSetSelectedDocument = false; - } + #region SelectedDocument - #endregion + /// + /// SelectedDocument Dependency Property + /// + public static readonly DependencyProperty SelectedDocumentProperty = + DependencyProperty.Register( "SelectedDocument", typeof( LayoutDocumentItem ), typeof( NavigatorWindow ), + new FrameworkPropertyMetadata( ( LayoutDocumentItem )null, + new PropertyChangedCallback( OnSelectedDocumentChanged ) ) ); - #region SelectedAnchorable + /// + /// Gets or sets the SelectedDocument property. This dependency property + /// indicates the selected document. + /// + public LayoutDocumentItem SelectedDocument + { + get + { + return ( LayoutDocumentItem )GetValue( SelectedDocumentProperty ); + } + set + { + SetValue( SelectedDocumentProperty, value ); + } + } - /// - /// SelectedAnchorable Dependency Property - /// - public static readonly DependencyProperty SelectedAnchorableProperty = - DependencyProperty.Register("SelectedAnchorable", typeof(LayoutAnchorableItem), typeof(NavigatorWindow), - new FrameworkPropertyMetadata((LayoutAnchorableItem)null, - new PropertyChangedCallback(OnSelectedAnchorableChanged))); + /// + /// Handles changes to the SelectedDocument property. + /// + private static void OnSelectedDocumentChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( NavigatorWindow )d ).OnSelectedDocumentChanged( e ); + } - /// - /// Gets or sets the SelectedAnchorable property. This dependency property - /// indicates the selected anchorable. - /// - public LayoutAnchorableItem SelectedAnchorable - { - get { return (LayoutAnchorableItem)GetValue(SelectedAnchorableProperty); } - set { SetValue(SelectedAnchorableProperty, value); } - } + /// + /// Provides derived classes an opportunity to handle changes to the SelectedDocument property. + /// + protected virtual void OnSelectedDocumentChanged( DependencyPropertyChangedEventArgs e ) + { + if( _internalSetSelectedDocument ) + return; - /// - /// Handles changes to the SelectedAnchorable property. - /// - private static void OnSelectedAnchorableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((NavigatorWindow)d).OnSelectedAnchorableChanged(e); - } + if( SelectedDocument != null && + SelectedDocument.ActivateCommand.CanExecute( null ) ) + { + SelectedDocument.ActivateCommand.Execute( null ); + Hide(); + } - /// - /// Provides derived classes an opportunity to handle changes to the SelectedAnchorable property. - /// - protected virtual void OnSelectedAnchorableChanged(DependencyPropertyChangedEventArgs e) - { - var selectedAnchorable = e.NewValue as LayoutAnchorableItem; - if (SelectedAnchorable != null && - SelectedAnchorable.ActivateCommand.CanExecute(null)) - { - SelectedAnchorable.ActivateCommand.Execute(null); - Close(); - } - } + } - #endregion + bool _internalSetSelectedDocument = false; + void InternalSetSelectedDocument( LayoutDocumentItem documentToSelect ) + { + _internalSetSelectedDocument = true; + SelectedDocument = documentToSelect; + _internalSetSelectedDocument = false; + } + #endregion - internal void SelectNextDocument() - { - if (SelectedDocument != null) - { - int docIndex = Documents.IndexOf(SelectedDocument); - docIndex++; - if (docIndex == Documents.Length) - docIndex = 0; - InternalSetSelectedDocument(Documents[docIndex]); - } + #region SelectedAnchorable - } + /// + /// SelectedAnchorable Dependency Property + /// + public static readonly DependencyProperty SelectedAnchorableProperty = + DependencyProperty.Register( "SelectedAnchorable", typeof( LayoutAnchorableItem ), typeof( NavigatorWindow ), + new FrameworkPropertyMetadata( ( LayoutAnchorableItem )null, + new PropertyChangedCallback( OnSelectedAnchorableChanged ) ) ); - protected override void OnKeyDown(System.Windows.Input.KeyEventArgs e) - { - base.OnKeyDown(e); - } + /// + /// Gets or sets the SelectedAnchorable property. This dependency property + /// indicates the selected anchorable. + /// + public LayoutAnchorableItem SelectedAnchorable + { + get + { + return ( LayoutAnchorableItem )GetValue( SelectedAnchorableProperty ); + } + set + { + SetValue( SelectedAnchorableProperty, value ); + } + } - protected override void OnPreviewKeyDown(System.Windows.Input.KeyEventArgs e) - { - if (e.Key == System.Windows.Input.Key.Tab) - { - SelectNextDocument(); - e.Handled = true; - } + /// + /// Handles changes to the SelectedAnchorable property. + /// + private static void OnSelectedAnchorableChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( NavigatorWindow )d ).OnSelectedAnchorableChanged( e ); + } + /// + /// Provides derived classes an opportunity to handle changes to the SelectedAnchorable property. + /// + protected virtual void OnSelectedAnchorableChanged( DependencyPropertyChangedEventArgs e ) + { + var selectedAnchorable = e.NewValue as LayoutAnchorableItem; + if( SelectedAnchorable != null && + SelectedAnchorable.ActivateCommand.CanExecute( null ) ) + { + SelectedAnchorable.ActivateCommand.Execute( null ); + Close(); + } + } - base.OnPreviewKeyDown(e); - } + #endregion - protected override void OnPreviewKeyUp(System.Windows.Input.KeyEventArgs e) - { - if (e.Key != System.Windows.Input.Key.Tab) - { - if (SelectedAnchorable != null && - SelectedAnchorable.ActivateCommand.CanExecute(null)) - SelectedAnchorable.ActivateCommand.Execute(null); - - if (SelectedAnchorable == null && - SelectedDocument != null && - SelectedDocument.ActivateCommand.CanExecute(null)) - SelectedDocument.ActivateCommand.Execute(null); - Close(); - e.Handled = true; - } - - - base.OnPreviewKeyUp(e); - } + internal void SelectNextDocument() + { + if( SelectedDocument != null ) + { + int docIndex = Documents.IndexOf( SelectedDocument ); + docIndex++; + if( docIndex == Documents.Length ) + docIndex = 0; + InternalSetSelectedDocument( Documents[ docIndex ] ); + } + + } + + protected override void OnKeyDown( System.Windows.Input.KeyEventArgs e ) + { + base.OnKeyDown( e ); } + + protected override void OnPreviewKeyDown( System.Windows.Input.KeyEventArgs e ) + { + if( e.Key == System.Windows.Input.Key.Tab ) + { + SelectNextDocument(); + e.Handled = true; + } + + + base.OnPreviewKeyDown( e ); + } + + protected override void OnPreviewKeyUp( System.Windows.Input.KeyEventArgs e ) + { + if( e.Key != System.Windows.Input.Key.Tab ) + { + if( SelectedAnchorable != null && + SelectedAnchorable.ActivateCommand.CanExecute( null ) ) + SelectedAnchorable.ActivateCommand.Execute( null ); + + if( SelectedAnchorable == null && + SelectedDocument != null && + SelectedDocument.ActivateCommand.CanExecute( null ) ) + SelectedDocument.ActivateCommand.Execute( null ); + Close(); + e.Handled = true; + } + + + base.OnPreviewKeyUp( e ); + } + + + } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Converters/AnchorableContextMenuHideVisibilityConverter.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Converters/AnchorableContextMenuHideVisibilityConverter.cs new file mode 100644 index 00000000..7c881eba --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Converters/AnchorableContextMenuHideVisibilityConverter.cs @@ -0,0 +1,49 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Globalization; +using System.Linq; +using System.Windows; +using System.Windows.Data; + +namespace Xceed.Wpf.AvalonDock.Converters +{ + public class AnchorableContextMenuHideVisibilityConverter : IMultiValueConverter + { + public object Convert( object[] values, Type targetType, object parameter, CultureInfo culture ) + { + if( ( values.Count() == 2 ) + && ( values[ 0 ] != DependencyProperty.UnsetValue ) + && ( values[ 1 ] != DependencyProperty.UnsetValue ) + && ( values[ 1 ] is bool )) + { + var canClose = ( bool )values[ 1 ]; + + return canClose ? Visibility.Collapsed : values[ 0 ]; + } + else + { + return values[ 0 ]; + } + } + + public object[] ConvertBack( object value, Type[] targetTypes, object parameter, CultureInfo culture ) + { + throw new NotImplementedException(); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/DockingManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/DockingManager.cs index 2ed4f6c1..2456e496 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/DockingManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/DockingManager.cs @@ -17,14 +17,11 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Windows.Controls; using System.Windows; using System.Windows.Markup; using System.ComponentModel; using System.Windows.Interop; -using System.Diagnostics; - using Xceed.Wpf.AvalonDock.Layout; using Xceed.Wpf.AvalonDock.Controls; using System.Windows.Input; @@ -32,3219 +29,3479 @@ using System.Collections; using System.Collections.Specialized; using System.Windows.Data; using System.Windows.Threading; -using Xceed.Wpf.AvalonDock.Commands; using Xceed.Wpf.AvalonDock.Themes; namespace Xceed.Wpf.AvalonDock { - [ContentProperty("Layout")] - [TemplatePart(Name="PART_AutoHideArea")] - public class DockingManager : Control, IOverlayWindowHost//, ILogicalChildrenContainer - { - private ResourceDictionary currentThemeResourceDictionary; // = null + [ContentProperty( "Layout" )] + [TemplatePart( Name = "PART_AutoHideArea" )] + public class DockingManager : Control, IOverlayWindowHost//, ILogicalChildrenContainer + { + private ResourceDictionary currentThemeResourceDictionary; // = null - static DockingManager() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(DockingManager), new FrameworkPropertyMetadata(typeof(DockingManager))); - FocusableProperty.OverrideMetadata(typeof(DockingManager), new FrameworkPropertyMetadata(false)); - HwndSource.DefaultAcquireHwndFocusInMenuMode = false; - } + static DockingManager() + { + DefaultStyleKeyProperty.OverrideMetadata( typeof( DockingManager ), new FrameworkPropertyMetadata( typeof( DockingManager ) ) ); + FocusableProperty.OverrideMetadata( typeof( DockingManager ), new FrameworkPropertyMetadata( false ) ); + HwndSource.DefaultAcquireHwndFocusInMenuMode = false; + } - public DockingManager() - { + public DockingManager() + { #if !VS2008 - Layout = new LayoutRoot() { RootPanel = new LayoutPanel(new LayoutDocumentPaneGroup(new LayoutDocumentPane())) }; + Layout = new LayoutRoot() { RootPanel = new LayoutPanel( new LayoutDocumentPaneGroup( new LayoutDocumentPane() ) ) }; #else this.SetCurrentValue( DockingManager.LayoutProperty, new LayoutRoot() { RootPanel = new LayoutPanel(new LayoutDocumentPaneGroup(new LayoutDocumentPane())) } ); #endif - this.Loaded += new RoutedEventHandler(DockingManager_Loaded); - this.Unloaded += new RoutedEventHandler(DockingManager_Unloaded); - } - - #region Layout - - /// - /// Layout Dependency Property - /// - public static readonly DependencyProperty LayoutProperty = - DependencyProperty.Register("Layout", typeof(LayoutRoot), typeof(DockingManager), - new FrameworkPropertyMetadata(null, - new PropertyChangedCallback(OnLayoutChanged), - new CoerceValueCallback(CoerceLayoutValue))); - - /// - /// Gets or sets the Layout property. This dependency property - /// indicates layout tree. - /// - public LayoutRoot Layout - { - get { return (LayoutRoot)GetValue(LayoutProperty); } - set { SetValue(LayoutProperty, value); } - } - - /// - /// Handles changes to the Layout property. - /// - private static void OnLayoutChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnLayoutChanged(e.OldValue as LayoutRoot, e.NewValue as LayoutRoot); - } - - /// - /// Provides derived classes an opportunity to handle changes to the property. - /// - protected virtual void OnLayoutChanged(LayoutRoot oldLayout, LayoutRoot newLayout) - { - if (oldLayout != null) - { - oldLayout.PropertyChanged -= new PropertyChangedEventHandler(OnLayoutRootPropertyChanged); - oldLayout.Updated -= new EventHandler(OnLayoutRootUpdated); - } - - foreach (var fwc in _fwList.ToArray()) - { - fwc.KeepContentVisibleOnClose = true; - fwc.InternalClose(); - } - - _fwList.Clear(); - - DetachDocumentsSource(oldLayout, DocumentsSource); - DetachAnchorablesSource(oldLayout, AnchorablesSource); - - if (oldLayout != null && - oldLayout.Manager == this) - oldLayout.Manager = null; - - ClearLogicalChildrenList(); - DetachLayoutItems(); + this.Loaded += new RoutedEventHandler( DockingManager_Loaded ); + this.Unloaded += new RoutedEventHandler( DockingManager_Unloaded ); + } - Layout.Manager = this; + #region Layout + + /// + /// Layout Dependency Property + /// + public static readonly DependencyProperty LayoutProperty = + DependencyProperty.Register( "Layout", typeof( LayoutRoot ), typeof( DockingManager ), + new FrameworkPropertyMetadata( null, + new PropertyChangedCallback( OnLayoutChanged ), + new CoerceValueCallback( CoerceLayoutValue ) ) ); + + /// + /// Gets or sets the Layout property. This dependency property + /// indicates layout tree. + /// + public LayoutRoot Layout + { + get + { + return ( LayoutRoot )GetValue( LayoutProperty ); + } + set + { + SetValue( LayoutProperty, value ); + } + } - AttachLayoutItems(); - AttachDocumentsSource(newLayout, DocumentsSource); - AttachAnchorablesSource(newLayout, AnchorablesSource); + /// + /// Handles changes to the Layout property. + /// + private static void OnLayoutChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnLayoutChanged( e.OldValue as LayoutRoot, e.NewValue as LayoutRoot ); + } - if (IsLoaded) - { - LayoutRootPanel = CreateUIElementForModel(Layout.RootPanel) as LayoutPanelControl; - LeftSidePanel = CreateUIElementForModel(Layout.LeftSide) as LayoutAnchorSideControl; - TopSidePanel = CreateUIElementForModel(Layout.TopSide) as LayoutAnchorSideControl; - RightSidePanel = CreateUIElementForModel(Layout.RightSide) as LayoutAnchorSideControl; - BottomSidePanel = CreateUIElementForModel(Layout.BottomSide) as LayoutAnchorSideControl; + /// + /// Provides derived classes an opportunity to handle changes to the property. + /// + protected virtual void OnLayoutChanged( LayoutRoot oldLayout, LayoutRoot newLayout ) + { + if( oldLayout != null ) + { + oldLayout.PropertyChanged -= new PropertyChangedEventHandler( OnLayoutRootPropertyChanged ); + oldLayout.Updated -= new EventHandler( OnLayoutRootUpdated ); + } - foreach (var fw in Layout.FloatingWindows.ToArray()) - { - if (fw.IsValid) - _fwList.Add(CreateUIElementForModel(fw) as LayoutFloatingWindowControl); - } + foreach( var fwc in _fwList.ToArray() ) + { + fwc.KeepContentVisibleOnClose = true; + fwc.InternalClose(); + } - foreach (var fw in _fwList) - { - //fw.Owner = Window.GetWindow(this); - //fw.SetParentToMainWindowOf(this); - } - } + _fwList.Clear(); + DetachDocumentsSource( oldLayout, DocumentsSource ); + DetachAnchorablesSource( oldLayout, AnchorablesSource ); - if (newLayout != null) - { - newLayout.PropertyChanged += new PropertyChangedEventHandler(OnLayoutRootPropertyChanged); - newLayout.Updated += new EventHandler(OnLayoutRootUpdated); - } + if( oldLayout != null && + oldLayout.Manager == this ) + oldLayout.Manager = null; - if (LayoutChanged != null) - LayoutChanged(this, EventArgs.Empty); + ClearLogicalChildrenList(); + DetachLayoutItems(); - //if (Layout != null) - // Layout.CollectGarbage(); + Layout.Manager = this; - CommandManager.InvalidateRequerySuggested(); - } + AttachLayoutItems(); + AttachDocumentsSource( newLayout, DocumentsSource ); + AttachAnchorablesSource( newLayout, AnchorablesSource ); - // DispatcherOperation _setFocusAsyncOperation = null; + if( IsLoaded ) + { + LayoutRootPanel = CreateUIElementForModel( Layout.RootPanel ) as LayoutPanelControl; + LeftSidePanel = CreateUIElementForModel( Layout.LeftSide ) as LayoutAnchorSideControl; + TopSidePanel = CreateUIElementForModel( Layout.TopSide ) as LayoutAnchorSideControl; + RightSidePanel = CreateUIElementForModel( Layout.RightSide ) as LayoutAnchorSideControl; + BottomSidePanel = CreateUIElementForModel( Layout.BottomSide ) as LayoutAnchorSideControl; - void OnLayoutRootPropertyChanged(object sender, PropertyChangedEventArgs e) + foreach( var fw in Layout.FloatingWindows.ToArray() ) { - if (e.PropertyName == "RootPanel") - { - if (IsInitialized) - { - var layoutRootPanel = CreateUIElementForModel(Layout.RootPanel) as LayoutPanelControl; - LayoutRootPanel = layoutRootPanel; - } - } - else if (e.PropertyName == "ActiveContent") - { - if (Layout.ActiveContent != null) - { - //Debug.WriteLine(new StackTrace().ToString()); - - //set focus on active element only after a layout pass is completed - //it's possible that it is not yet visible in the visual tree - //if (_setFocusAsyncOperation == null) - //{ - // _setFocusAsyncOperation = Dispatcher.BeginInvoke(new Action(() => - // { - if (Layout.ActiveContent != null) - FocusElementManager.SetFocusOnLastElement(Layout.ActiveContent); - //_setFocusAsyncOperation = null; - // } ), DispatcherPriority.Input ); - //} - } - - //if (!_insideInternalSetActiveContent) - // ActiveContent = Layout.ActiveContent != null ? - // Layout.ActiveContent.Content : null; - if( !_insideInternalSetActiveContent && (Layout.ActiveContent != null) ) - { - this.ActiveContent = Layout.ActiveContent.Content; - } - } + if( fw.IsValid ) + _fwList.Add( CreateUIElementForModel( fw ) as LayoutFloatingWindowControl ); } - void OnLayoutRootUpdated(object sender, EventArgs e) + foreach( var fw in _fwList ) { - CommandManager.InvalidateRequerySuggested(); + //fw.Owner = Window.GetWindow(this); + //fw.SetParentToMainWindowOf(this); } + } - /// - /// Event fired when property changes - /// - public event EventHandler LayoutChanged; - - /// - /// Coerces the value. - /// - private static object CoerceLayoutValue(DependencyObject d, object value) - { - if (value == null) - return new LayoutRoot() { RootPanel = new LayoutPanel(new LayoutDocumentPaneGroup(new LayoutDocumentPane())) }; - - ((DockingManager)d).OnLayoutChanging(value as LayoutRoot); - - return value; - } - - /// - /// Event fired when property is about to be changed - /// - public event EventHandler LayoutChanging; + if( newLayout != null ) + { + newLayout.PropertyChanged += new PropertyChangedEventHandler( OnLayoutRootPropertyChanged ); + newLayout.Updated += new EventHandler( OnLayoutRootUpdated ); + } - void OnLayoutChanging(LayoutRoot newLayout) - { - if (LayoutChanging != null) - LayoutChanging(this, EventArgs.Empty); - } + if( LayoutChanged != null ) + LayoutChanged( this, EventArgs.Empty ); + //if (Layout != null) + // Layout.CollectGarbage(); - #region LayoutUpdateStrategy + CommandManager.InvalidateRequerySuggested(); + } - /// - /// LayoutUpdateStrategy Dependency Property - /// - public static readonly DependencyProperty LayoutUpdateStrategyProperty = - DependencyProperty.Register("LayoutUpdateStrategy", typeof(ILayoutUpdateStrategy), typeof(DockingManager), - new FrameworkPropertyMetadata((ILayoutUpdateStrategy)null)); + // DispatcherOperation _setFocusAsyncOperation = null; - /// - /// Gets or sets the LayoutUpdateStrategy property. This dependency property - /// indicates the strategy class to call when AvalonDock needs to positionate a LayoutAnchorable inside an existing layout. - /// - /// Sometimes it's impossible to automatically insert an anchorable in the layout without specifing the target parent pane. - /// Set this property to an object that will be asked to insert the anchorable to the desidered position. - public ILayoutUpdateStrategy LayoutUpdateStrategy + void OnLayoutRootPropertyChanged( object sender, PropertyChangedEventArgs e ) + { + if( e.PropertyName == "RootPanel" ) + { + if( IsInitialized ) { - get { return (ILayoutUpdateStrategy)GetValue(LayoutUpdateStrategyProperty); } - set { SetValue(LayoutUpdateStrategyProperty, value); } + var layoutRootPanel = CreateUIElementForModel( Layout.RootPanel ) as LayoutPanelControl; + LayoutRootPanel = layoutRootPanel; } - - #endregion - - - - #endregion - - public override void OnApplyTemplate() + } + else if( e.PropertyName == "ActiveContent" ) + { + if( Layout.ActiveContent != null ) { - base.OnApplyTemplate(); + //Debug.WriteLine(new StackTrace().ToString()); - // SetupAutoHideWindow(); + //set focus on active element only after a layout pass is completed + //it's possible that it is not yet visible in the visual tree + //if (_setFocusAsyncOperation == null) + //{ + // _setFocusAsyncOperation = Dispatcher.BeginInvoke(new Action(() => + // { + if( Layout.ActiveContent != null ) + FocusElementManager.SetFocusOnLastElement( Layout.ActiveContent ); + //_setFocusAsyncOperation = null; + // } ), DispatcherPriority.Input ); + //} } - protected override void OnInitialized( EventArgs e ) + //if (!_insideInternalSetActiveContent) + // ActiveContent = Layout.ActiveContent != null ? + // Layout.ActiveContent.Content : null; + if( !_insideInternalSetActiveContent && ( Layout.ActiveContent != null ) ) { - base.OnInitialized(e); + this.ActiveContent = Layout.ActiveContent.Content; } + } + } - void DockingManager_Loaded(object sender, RoutedEventArgs e) - { - if (!DesignerProperties.GetIsInDesignMode(this)) - { - if( Layout.Manager == this ) - { - LayoutRootPanel = CreateUIElementForModel( Layout.RootPanel ) as LayoutPanelControl; - LeftSidePanel = CreateUIElementForModel( Layout.LeftSide ) as LayoutAnchorSideControl; - TopSidePanel = CreateUIElementForModel( Layout.TopSide ) as LayoutAnchorSideControl; - RightSidePanel = CreateUIElementForModel( Layout.RightSide ) as LayoutAnchorSideControl; - BottomSidePanel = CreateUIElementForModel( Layout.BottomSide ) as LayoutAnchorSideControl; - } + void OnLayoutRootUpdated( object sender, EventArgs e ) + { + CommandManager.InvalidateRequerySuggested(); + } - SetupAutoHideWindow(); - //load windows not already loaded! - foreach (var fw in Layout.FloatingWindows.Where(fw => !_fwList.Any(fwc => fwc.Model == fw))) - _fwList.Add(CreateUIElementForModel(fw) as LayoutFloatingWindowControl); + /// + /// Event fired when property changes + /// + public event EventHandler LayoutChanged; - //create the overlaywindow if it's possible - if (IsVisible) - CreateOverlayWindow(); - FocusElementManager.SetupFocusManagement(this); - } - } + /// + /// Coerces the value. + /// + private static object CoerceLayoutValue( DependencyObject d, object value ) + { + if( value == null ) + return new LayoutRoot() { RootPanel = new LayoutPanel( new LayoutDocumentPaneGroup( new LayoutDocumentPane() ) ) }; - void DockingManager_Unloaded(object sender, RoutedEventArgs e) - { + ( ( DockingManager )d ).OnLayoutChanging( value as LayoutRoot ); - if (!DesignerProperties.GetIsInDesignMode(this)) - { - if( _autoHideWindowManager != null ) - { - _autoHideWindowManager.HideAutoWindow(); - } + return value; + } - if( AutoHideWindow != null ) - AutoHideWindow.Dispose(); + /// + /// Event fired when property is about to be changed + /// + public event EventHandler LayoutChanging; - foreach (var fw in _fwList.ToArray()) - { - //fw.Owner = null; - fw.SetParentWindowToNull(); - fw.KeepContentVisibleOnClose = true; - fw.Close(); - } + void OnLayoutChanging( LayoutRoot newLayout ) + { + if( LayoutChanging != null ) + LayoutChanging( this, EventArgs.Empty ); + } - DestroyOverlayWindow(); - FocusElementManager.FinalizeFocusManagement(this); - } - } - internal UIElement CreateUIElementForModel(ILayoutElement model) - { - if (model is LayoutPanel) - return new LayoutPanelControl(model as LayoutPanel); - if (model is LayoutAnchorablePaneGroup) - return new LayoutAnchorablePaneGroupControl(model as LayoutAnchorablePaneGroup); - if (model is LayoutDocumentPaneGroup) - return new LayoutDocumentPaneGroupControl(model as LayoutDocumentPaneGroup); - - if (model is LayoutAnchorSide) - { - var templateModelView = new LayoutAnchorSideControl(model as LayoutAnchorSide); - templateModelView.SetBinding(LayoutAnchorSideControl.TemplateProperty, new Binding("AnchorSideTemplate") { Source = this }); - return templateModelView; - } - if (model is LayoutAnchorGroup) - { - var templateModelView = new LayoutAnchorGroupControl(model as LayoutAnchorGroup); - templateModelView.SetBinding(LayoutAnchorGroupControl.TemplateProperty, new Binding("AnchorGroupTemplate") { Source = this }); - return templateModelView; - } + #region LayoutUpdateStrategy - if (model is LayoutDocumentPane) - { - var templateModelView = new LayoutDocumentPaneControl(model as LayoutDocumentPane); - templateModelView.SetBinding(LayoutDocumentPaneControl.StyleProperty, new Binding("DocumentPaneControlStyle") { Source = this }); - return templateModelView; - } - if (model is LayoutAnchorablePane) - { - var templateModelView = new LayoutAnchorablePaneControl(model as LayoutAnchorablePane); - templateModelView.SetBinding(LayoutAnchorablePaneControl.StyleProperty, new Binding("AnchorablePaneControlStyle") { Source = this }); - return templateModelView; - } + /// + /// LayoutUpdateStrategy Dependency Property + /// + public static readonly DependencyProperty LayoutUpdateStrategyProperty = + DependencyProperty.Register( "LayoutUpdateStrategy", typeof( ILayoutUpdateStrategy ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( ILayoutUpdateStrategy )null ) ); - if (model is LayoutAnchorableFloatingWindow) - { - if (DesignerProperties.GetIsInDesignMode(this)) - return null; - var modelFW = model as LayoutAnchorableFloatingWindow; - var newFW = new LayoutAnchorableFloatingWindowControl(modelFW) - { - //Owner = Window.GetWindow(this) - }; - newFW.SetParentToMainWindowOf(this); + /// + /// Gets or sets the LayoutUpdateStrategy property. This dependency property + /// indicates the strategy class to call when AvalonDock needs to positionate a LayoutAnchorable inside an existing layout. + /// + /// Sometimes it's impossible to automatically insert an anchorable in the layout without specifing the target parent pane. + /// Set this property to an object that will be asked to insert the anchorable to the desidered position. + public ILayoutUpdateStrategy LayoutUpdateStrategy + { + get + { + return ( ILayoutUpdateStrategy )GetValue( LayoutUpdateStrategyProperty ); + } + set + { + SetValue( LayoutUpdateStrategyProperty, value ); + } + } - var paneForExtensions = modelFW.RootPanel.Children.OfType().FirstOrDefault(); - if (paneForExtensions != null) - { - //ensure that floating window position is inside current (or nearest) monitor - paneForExtensions.KeepInsideNearestMonitor(); + #endregion - newFW.Left = paneForExtensions.FloatingLeft; - newFW.Top = paneForExtensions.FloatingTop; - newFW.Width = paneForExtensions.FloatingWidth; - newFW.Height = paneForExtensions.FloatingHeight; - } - newFW.ShowInTaskbar = false; - newFW.Show(); - // Do not set the WindowState before showing or it will be lost - if( paneForExtensions != null && paneForExtensions.IsMaximized ) - { - newFW.WindowState = WindowState.Maximized; - } - return newFW; - } - if (model is LayoutDocumentFloatingWindow) - { - if (DesignerProperties.GetIsInDesignMode(this)) - return null; - var modelFW = model as LayoutDocumentFloatingWindow; - var newFW = new LayoutDocumentFloatingWindowControl(modelFW) - { - //Owner = Window.GetWindow(this) - }; - newFW.SetParentToMainWindowOf(this); + #endregion - var paneForExtensions = modelFW.RootDocument; - if (paneForExtensions != null) - { - //ensure that floating window position is inside current (or nearest) monitor - paneForExtensions.KeepInsideNearestMonitor(); + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); - newFW.Left = paneForExtensions.FloatingLeft; - newFW.Top = paneForExtensions.FloatingTop; - newFW.Width = paneForExtensions.FloatingWidth; - newFW.Height = paneForExtensions.FloatingHeight; - } - newFW.ShowInTaskbar = false; - newFW.Show(); - // Do not set the WindowState before showing or it will be lost - if( paneForExtensions != null && paneForExtensions.IsMaximized ) - { - newFW.WindowState = WindowState.Maximized; - } - return newFW; - } + _autohideArea = GetTemplateChild( "PART_AutoHideArea" ) as FrameworkElement; + } + + protected override void OnInitialized( EventArgs e ) + { + base.OnInitialized( e ); + } - if (model is LayoutDocument) - { - var templateModelView = new LayoutDocumentControl() { Model = model as LayoutDocument }; - return templateModelView; - } - return null; + void DockingManager_Loaded( object sender, RoutedEventArgs e ) + { + if( !DesignerProperties.GetIsInDesignMode( this ) ) + { + if( Layout.Manager == this ) + { + LayoutRootPanel = CreateUIElementForModel( Layout.RootPanel ) as LayoutPanelControl; + LeftSidePanel = CreateUIElementForModel( Layout.LeftSide ) as LayoutAnchorSideControl; + TopSidePanel = CreateUIElementForModel( Layout.TopSide ) as LayoutAnchorSideControl; + RightSidePanel = CreateUIElementForModel( Layout.RightSide ) as LayoutAnchorSideControl; + BottomSidePanel = CreateUIElementForModel( Layout.BottomSide ) as LayoutAnchorSideControl; } + SetupAutoHideWindow(); + //load windows not already loaded! + foreach( var fw in Layout.FloatingWindows.Where( fw => !_fwList.Any( fwc => fwc.Model == fw ) ) ) + _fwList.Add( CreateUIElementForModel( fw ) as LayoutFloatingWindowControl ); - #region DocumentPaneTemplate + //create the overlaywindow if it's possible + if( IsVisible ) + CreateOverlayWindow(); + FocusElementManager.SetupFocusManagement( this ); + } + } - /// - /// DocumentPaneTemplate Dependency Property - /// - public static readonly DependencyProperty DocumentPaneTemplateProperty = - DependencyProperty.Register("DocumentPaneTemplate", typeof(ControlTemplate), typeof(DockingManager), - new FrameworkPropertyMetadata((ControlTemplate)null, - new PropertyChangedCallback(OnDocumentPaneTemplateChanged))); + void DockingManager_Unloaded( object sender, RoutedEventArgs e ) + { - /// - /// Gets or sets the DocumentPaneDataTemplate property. This dependency property - /// indicates . - /// - public ControlTemplate DocumentPaneTemplate + if( !DesignerProperties.GetIsInDesignMode( this ) ) + { + if( _autoHideWindowManager != null ) { - get { return (ControlTemplate)GetValue(DocumentPaneTemplateProperty); } - set { SetValue(DocumentPaneTemplateProperty, value); } + _autoHideWindowManager.HideAutoWindow(); } - /// - /// Handles changes to the DocumentPaneTemplate property. - /// - private static void OnDocumentPaneTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnDocumentPaneTemplateChanged(e); - } + if( AutoHideWindow != null ) + AutoHideWindow.Dispose(); - /// - /// Provides derived classes an opportunity to handle changes to the DocumentPaneTemplate property. - /// - protected virtual void OnDocumentPaneTemplateChanged(DependencyPropertyChangedEventArgs e) + foreach( var fw in _fwList.ToArray() ) { + //fw.Owner = null; + fw.SetParentWindowToNull(); + fw.KeepContentVisibleOnClose = true; + fw.Close(); } - #endregion + DestroyOverlayWindow(); + FocusElementManager.FinalizeFocusManagement( this ); + } + } - #region AnchorablePaneTemplate + internal UIElement CreateUIElementForModel( ILayoutElement model ) + { + if( model is LayoutPanel ) + return new LayoutPanelControl( model as LayoutPanel ); + if( model is LayoutAnchorablePaneGroup ) + return new LayoutAnchorablePaneGroupControl( model as LayoutAnchorablePaneGroup ); + if( model is LayoutDocumentPaneGroup ) + return new LayoutDocumentPaneGroupControl( model as LayoutDocumentPaneGroup ); + + if( model is LayoutAnchorSide ) + { + var templateModelView = new LayoutAnchorSideControl( model as LayoutAnchorSide ); + templateModelView.SetBinding( LayoutAnchorSideControl.TemplateProperty, new Binding( "AnchorSideTemplate" ) { Source = this } ); + return templateModelView; + } + if( model is LayoutAnchorGroup ) + { + var templateModelView = new LayoutAnchorGroupControl( model as LayoutAnchorGroup ); + templateModelView.SetBinding( LayoutAnchorGroupControl.TemplateProperty, new Binding( "AnchorGroupTemplate" ) { Source = this } ); + return templateModelView; + } - /// - /// AnchorablePaneTemplate Dependency Property - /// - public static readonly DependencyProperty AnchorablePaneTemplateProperty = - DependencyProperty.Register("AnchorablePaneTemplate", typeof(ControlTemplate), typeof(DockingManager), - new FrameworkPropertyMetadata((ControlTemplate)null, - new PropertyChangedCallback(OnAnchorablePaneTemplateChanged))); + if( model is LayoutDocumentPane ) + { + var templateModelView = new LayoutDocumentPaneControl( model as LayoutDocumentPane ); + templateModelView.SetBinding( LayoutDocumentPaneControl.StyleProperty, new Binding( "DocumentPaneControlStyle" ) { Source = this } ); + return templateModelView; + } + if( model is LayoutAnchorablePane ) + { + var templateModelView = new LayoutAnchorablePaneControl( model as LayoutAnchorablePane ); + templateModelView.SetBinding( LayoutAnchorablePaneControl.StyleProperty, new Binding( "AnchorablePaneControlStyle" ) { Source = this } ); + return templateModelView; + } - /// - /// Gets or sets the AnchorablePaneTemplate property. This dependency property - /// indicates .... - /// - public ControlTemplate AnchorablePaneTemplate + if( model is LayoutAnchorableFloatingWindow ) + { + if( DesignerProperties.GetIsInDesignMode( this ) ) + return null; + var modelFW = model as LayoutAnchorableFloatingWindow; + var newFW = new LayoutAnchorableFloatingWindowControl( modelFW ) { - get { return (ControlTemplate)GetValue(AnchorablePaneTemplateProperty); } - set { SetValue(AnchorablePaneTemplateProperty, value); } - } + //Owner = Window.GetWindow(this) + }; + newFW.SetParentToMainWindowOf( this ); - /// - /// Handles changes to the AnchorablePaneDataTemplate property. - /// - private static void OnAnchorablePaneTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + var paneForExtensions = modelFW.RootPanel.Children.OfType().FirstOrDefault(); + if( paneForExtensions != null ) { - ((DockingManager)d).OnAnchorablePaneTemplateChanged(e); - } + //ensure that floating window position is inside current (or nearest) monitor + paneForExtensions.KeepInsideNearestMonitor(); - /// - /// Provides derived classes an opportunity to handle changes to the AnchorablePaneDataTemplate property. - /// - protected virtual void OnAnchorablePaneTemplateChanged(DependencyPropertyChangedEventArgs e) - { + newFW.Left = paneForExtensions.FloatingLeft; + newFW.Top = paneForExtensions.FloatingTop; + newFW.Width = paneForExtensions.FloatingWidth; + newFW.Height = paneForExtensions.FloatingHeight; } - #endregion - - #region AnchorSideTemplate - - /// - /// AnchorSideTemplate Dependency Property - /// - public static readonly DependencyProperty AnchorSideTemplateProperty = - DependencyProperty.Register("AnchorSideTemplate", typeof(ControlTemplate), typeof(DockingManager), - new FrameworkPropertyMetadata((ControlTemplate)null)); - - /// - /// Gets or sets the AnchorSideTemplate property. This dependency property - /// indicates .... - /// - public ControlTemplate AnchorSideTemplate + newFW.ShowInTaskbar = false; + newFW.Show(); + // Do not set the WindowState before showing or it will be lost + if( paneForExtensions != null && paneForExtensions.IsMaximized ) { - get { return (ControlTemplate)GetValue(AnchorSideTemplateProperty); } - set { SetValue(AnchorSideTemplateProperty, value); } + newFW.WindowState = WindowState.Maximized; } + return newFW; + } - #endregion - - #region AnchorGroupTemplate - - /// - /// AnchorGroupTemplate Dependency Property - /// - public static readonly DependencyProperty AnchorGroupTemplateProperty = - DependencyProperty.Register("AnchorGroupTemplate", typeof(ControlTemplate), typeof(DockingManager), - new FrameworkPropertyMetadata((ControlTemplate)null)); - - /// - /// Gets or sets the AnchorGroupTemplate property. This dependency property - /// indicates the template used to render the AnchorGroup control. - /// - public ControlTemplate AnchorGroupTemplate + if( model is LayoutDocumentFloatingWindow ) + { + if( DesignerProperties.GetIsInDesignMode( this ) ) + return null; + var modelFW = model as LayoutDocumentFloatingWindow; + var newFW = new LayoutDocumentFloatingWindowControl( modelFW ) { - get { return (ControlTemplate)GetValue(AnchorGroupTemplateProperty); } - set { SetValue(AnchorGroupTemplateProperty, value); } - } - - #endregion + //Owner = Window.GetWindow(this) + }; + newFW.SetParentToMainWindowOf( this ); - #region AnchorTemplate + var paneForExtensions = modelFW.RootDocument; + if( paneForExtensions != null ) + { + //ensure that floating window position is inside current (or nearest) monitor + paneForExtensions.KeepInsideNearestMonitor(); - /// - /// AnchorTemplate Dependency Property - /// - public static readonly DependencyProperty AnchorTemplateProperty = - DependencyProperty.Register("AnchorTemplate", typeof(ControlTemplate), typeof(DockingManager), - new FrameworkPropertyMetadata((ControlTemplate)null)); + newFW.Left = paneForExtensions.FloatingLeft; + newFW.Top = paneForExtensions.FloatingTop; + newFW.Width = paneForExtensions.FloatingWidth; + newFW.Height = paneForExtensions.FloatingHeight; + } - /// - /// Gets or sets the AnchorTemplate property. This dependency property - /// indicates .... - /// - public ControlTemplate AnchorTemplate + newFW.ShowInTaskbar = false; + newFW.Show(); + // Do not set the WindowState before showing or it will be lost + if( paneForExtensions != null && paneForExtensions.IsMaximized ) { - get { return (ControlTemplate)GetValue(AnchorTemplateProperty); } - set { SetValue(AnchorTemplateProperty, value); } + newFW.WindowState = WindowState.Maximized; } + return newFW; + } - #endregion - - #region DocumentPaneControlStyle + if( model is LayoutDocument ) + { + var templateModelView = new LayoutDocumentControl() { Model = model as LayoutDocument }; + return templateModelView; + } - /// - /// DocumentPaneControlStyle Dependency Property - /// - public static readonly DependencyProperty DocumentPaneControlStyleProperty = - DependencyProperty.Register("DocumentPaneControlStyle", typeof(Style), typeof(DockingManager), - new FrameworkPropertyMetadata((Style)null, - new PropertyChangedCallback(OnDocumentPaneControlStyleChanged))); + return null; + } - /// - /// Gets or sets the DocumentPaneControlStyle property. This dependency property - /// indicates .... - /// - public Style DocumentPaneControlStyle - { - get { return (Style)GetValue(DocumentPaneControlStyleProperty); } - set { SetValue(DocumentPaneControlStyleProperty, value); } - } - /// - /// Handles changes to the DocumentPaneControlStyle property. - /// - private static void OnDocumentPaneControlStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnDocumentPaneControlStyleChanged(e); - } - /// - /// Provides derived classes an opportunity to handle changes to the DocumentPaneControlStyle property. - /// - protected virtual void OnDocumentPaneControlStyleChanged(DependencyPropertyChangedEventArgs e) - { - } + #region DocumentPaneTemplate - #endregion + /// + /// DocumentPaneTemplate Dependency Property + /// + public static readonly DependencyProperty DocumentPaneTemplateProperty = + DependencyProperty.Register( "DocumentPaneTemplate", typeof( ControlTemplate ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( ControlTemplate )null, + new PropertyChangedCallback( OnDocumentPaneTemplateChanged ) ) ); - #region AnchorablePaneControlStyle + /// + /// Gets or sets the DocumentPaneDataTemplate property. This dependency property + /// indicates . + /// + public ControlTemplate DocumentPaneTemplate + { + get + { + return ( ControlTemplate )GetValue( DocumentPaneTemplateProperty ); + } + set + { + SetValue( DocumentPaneTemplateProperty, value ); + } + } - /// - /// AnchorablePaneControlStyle Dependency Property - /// - public static readonly DependencyProperty AnchorablePaneControlStyleProperty = - DependencyProperty.Register("AnchorablePaneControlStyle", typeof(Style), typeof(DockingManager), - new FrameworkPropertyMetadata((Style)null, - new PropertyChangedCallback(OnAnchorablePaneControlStyleChanged))); + /// + /// Handles changes to the DocumentPaneTemplate property. + /// + private static void OnDocumentPaneTemplateChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnDocumentPaneTemplateChanged( e ); + } - /// - /// Gets or sets the AnchorablePaneControlStyle property. This dependency property - /// indicates the style to apply to AnchorablePaneControl. - /// - public Style AnchorablePaneControlStyle - { - get { return (Style)GetValue(AnchorablePaneControlStyleProperty); } - set { SetValue(AnchorablePaneControlStyleProperty, value); } - } + /// + /// Provides derived classes an opportunity to handle changes to the DocumentPaneTemplate property. + /// + protected virtual void OnDocumentPaneTemplateChanged( DependencyPropertyChangedEventArgs e ) + { + } - /// - /// Handles changes to the AnchorablePaneControlStyle property. - /// - private static void OnAnchorablePaneControlStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnAnchorablePaneControlStyleChanged(e); - } + #endregion - /// - /// Provides derived classes an opportunity to handle changes to the AnchorablePaneControlStyle property. - /// - protected virtual void OnAnchorablePaneControlStyleChanged(DependencyPropertyChangedEventArgs e) - { - } + #region AnchorablePaneTemplate - #endregion + /// + /// AnchorablePaneTemplate Dependency Property + /// + public static readonly DependencyProperty AnchorablePaneTemplateProperty = + DependencyProperty.Register( "AnchorablePaneTemplate", typeof( ControlTemplate ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( ControlTemplate )null, + new PropertyChangedCallback( OnAnchorablePaneTemplateChanged ) ) ); - #region DocumentHeaderTemplate + /// + /// Gets or sets the AnchorablePaneTemplate property. This dependency property + /// indicates .... + /// + public ControlTemplate AnchorablePaneTemplate + { + get + { + return ( ControlTemplate )GetValue( AnchorablePaneTemplateProperty ); + } + set + { + SetValue( AnchorablePaneTemplateProperty, value ); + } + } - /// - /// DocumentHeaderTemplate Dependency Property - /// - public static readonly DependencyProperty DocumentHeaderTemplateProperty = - DependencyProperty.Register("DocumentHeaderTemplate", typeof(DataTemplate), typeof(DockingManager), - new FrameworkPropertyMetadata((DataTemplate)null, - new PropertyChangedCallback(OnDocumentHeaderTemplateChanged), - new CoerceValueCallback(CoerceDocumentHeaderTemplateValue))); + /// + /// Handles changes to the AnchorablePaneDataTemplate property. + /// + private static void OnAnchorablePaneTemplateChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnAnchorablePaneTemplateChanged( e ); + } - /// - /// Gets or sets the DocumentHeaderTemplate property. This dependency property - /// indicates data template to use for document header. - /// - public DataTemplate DocumentHeaderTemplate - { - get { return (DataTemplate)GetValue(DocumentHeaderTemplateProperty); } - set { SetValue(DocumentHeaderTemplateProperty, value); } - } + /// + /// Provides derived classes an opportunity to handle changes to the AnchorablePaneDataTemplate property. + /// + protected virtual void OnAnchorablePaneTemplateChanged( DependencyPropertyChangedEventArgs e ) + { + } - /// - /// Handles changes to the DocumentHeaderTemplate property. - /// - private static void OnDocumentHeaderTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnDocumentHeaderTemplateChanged(e); - } + #endregion - /// - /// Provides derived classes an opportunity to handle changes to the DocumentHeaderTemplate property. - /// - protected virtual void OnDocumentHeaderTemplateChanged(DependencyPropertyChangedEventArgs e) - { - } + #region AnchorSideTemplate - /// - /// Coerces the DocumentHeaderTemplate value. - /// - private static object CoerceDocumentHeaderTemplateValue(DependencyObject d, object value) - { - if (value != null && - d.GetValue(DocumentHeaderTemplateSelectorProperty) != null) - return null; - return value; - } + /// + /// AnchorSideTemplate Dependency Property + /// + public static readonly DependencyProperty AnchorSideTemplateProperty = + DependencyProperty.Register( "AnchorSideTemplate", typeof( ControlTemplate ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( ControlTemplate )null ) ); - #endregion + /// + /// Gets or sets the AnchorSideTemplate property. This dependency property + /// indicates .... + /// + public ControlTemplate AnchorSideTemplate + { + get + { + return ( ControlTemplate )GetValue( AnchorSideTemplateProperty ); + } + set + { + SetValue( AnchorSideTemplateProperty, value ); + } + } - #region DocumentHeaderTemplateSelector + #endregion - /// - /// DocumentHeaderTemplateSelector Dependency Property - /// - public static readonly DependencyProperty DocumentHeaderTemplateSelectorProperty = - DependencyProperty.Register("DocumentHeaderTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), - new FrameworkPropertyMetadata((DataTemplateSelector)null, - new PropertyChangedCallback(OnDocumentHeaderTemplateSelectorChanged), - new CoerceValueCallback(CoerceDocumentHeaderTemplateSelectorValue))); + #region AnchorGroupTemplate - /// - /// Gets or sets the DocumentHeaderTemplateSelector property. This dependency property - /// indicates the template selector that is used when selcting the data template for the header. - /// - public DataTemplateSelector DocumentHeaderTemplateSelector - { - get { return (DataTemplateSelector)GetValue(DocumentHeaderTemplateSelectorProperty); } - set { SetValue(DocumentHeaderTemplateSelectorProperty, value); } - } + /// + /// AnchorGroupTemplate Dependency Property + /// + public static readonly DependencyProperty AnchorGroupTemplateProperty = + DependencyProperty.Register( "AnchorGroupTemplate", typeof( ControlTemplate ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( ControlTemplate )null ) ); - /// - /// Handles changes to the DocumentHeaderTemplateSelector property. - /// - private static void OnDocumentHeaderTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnDocumentHeaderTemplateSelectorChanged(e); - } + /// + /// Gets or sets the AnchorGroupTemplate property. This dependency property + /// indicates the template used to render the AnchorGroup control. + /// + public ControlTemplate AnchorGroupTemplate + { + get + { + return ( ControlTemplate )GetValue( AnchorGroupTemplateProperty ); + } + set + { + SetValue( AnchorGroupTemplateProperty, value ); + } + } - /// - /// Provides derived classes an opportunity to handle changes to the DocumentHeaderTemplateSelector property. - /// - protected virtual void OnDocumentHeaderTemplateSelectorChanged(DependencyPropertyChangedEventArgs e) - { - if (e.NewValue != null && - DocumentHeaderTemplate != null) - DocumentHeaderTemplate = null; + #endregion - if (DocumentPaneMenuItemHeaderTemplateSelector == null) - DocumentPaneMenuItemHeaderTemplateSelector = DocumentHeaderTemplateSelector; + #region AnchorTemplate - } + /// + /// AnchorTemplate Dependency Property + /// + public static readonly DependencyProperty AnchorTemplateProperty = + DependencyProperty.Register( "AnchorTemplate", typeof( ControlTemplate ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( ControlTemplate )null ) ); - /// - /// Coerces the DocumentHeaderTemplateSelector value. - /// - private static object CoerceDocumentHeaderTemplateSelectorValue(DependencyObject d, object value) - { - return value; - } + /// + /// Gets or sets the AnchorTemplate property. This dependency property + /// indicates .... + /// + public ControlTemplate AnchorTemplate + { + get + { + return ( ControlTemplate )GetValue( AnchorTemplateProperty ); + } + set + { + SetValue( AnchorTemplateProperty, value ); + } + } - #endregion + #endregion - #region DocumentTitleTemplate + #region DocumentPaneControlStyle - /// - /// DocumentTitleTemplate Dependency Property - /// - public static readonly DependencyProperty DocumentTitleTemplateProperty = - DependencyProperty.Register("DocumentTitleTemplate", typeof(DataTemplate), typeof(DockingManager), - new FrameworkPropertyMetadata((DataTemplate)null, - new PropertyChangedCallback(OnDocumentTitleTemplateChanged), - new CoerceValueCallback(CoerceDocumentTitleTemplateValue))); + /// + /// DocumentPaneControlStyle Dependency Property + /// + public static readonly DependencyProperty DocumentPaneControlStyleProperty = + DependencyProperty.Register( "DocumentPaneControlStyle", typeof( Style ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( Style )null, + new PropertyChangedCallback( OnDocumentPaneControlStyleChanged ) ) ); - /// - /// Gets or sets the DocumentTitleTemplate property. This dependency property - /// indicates the datatemplate to use when creating the title for a document. - /// - public DataTemplate DocumentTitleTemplate - { - get { return (DataTemplate)GetValue(DocumentTitleTemplateProperty); } - set { SetValue(DocumentTitleTemplateProperty, value); } - } + /// + /// Gets or sets the DocumentPaneControlStyle property. This dependency property + /// indicates .... + /// + public Style DocumentPaneControlStyle + { + get + { + return ( Style )GetValue( DocumentPaneControlStyleProperty ); + } + set + { + SetValue( DocumentPaneControlStyleProperty, value ); + } + } - /// - /// Handles changes to the DocumentTitleTemplate property. - /// - private static void OnDocumentTitleTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnDocumentTitleTemplateChanged(e); - } + /// + /// Handles changes to the DocumentPaneControlStyle property. + /// + private static void OnDocumentPaneControlStyleChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnDocumentPaneControlStyleChanged( e ); + } - /// - /// Provides derived classes an opportunity to handle changes to the DocumentTitleTemplate property. - /// - protected virtual void OnDocumentTitleTemplateChanged(DependencyPropertyChangedEventArgs e) - { - } + /// + /// Provides derived classes an opportunity to handle changes to the DocumentPaneControlStyle property. + /// + protected virtual void OnDocumentPaneControlStyleChanged( DependencyPropertyChangedEventArgs e ) + { + } - /// - /// Coerces the DocumentTitleTemplate value. - /// - private static object CoerceDocumentTitleTemplateValue(DependencyObject d, object value) - { - if (value != null && - d.GetValue(DocumentTitleTemplateSelectorProperty) != null) - return null; + #endregion - return value; - } + #region AnchorablePaneControlStyle - #endregion + /// + /// AnchorablePaneControlStyle Dependency Property + /// + public static readonly DependencyProperty AnchorablePaneControlStyleProperty = + DependencyProperty.Register( "AnchorablePaneControlStyle", typeof( Style ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( Style )null, + new PropertyChangedCallback( OnAnchorablePaneControlStyleChanged ) ) ); - #region DocumentTitleTemplateSelector + /// + /// Gets or sets the AnchorablePaneControlStyle property. This dependency property + /// indicates the style to apply to AnchorablePaneControl. + /// + public Style AnchorablePaneControlStyle + { + get + { + return ( Style )GetValue( AnchorablePaneControlStyleProperty ); + } + set + { + SetValue( AnchorablePaneControlStyleProperty, value ); + } + } - /// - /// DocumentTitleTemplateSelector Dependency Property - /// - public static readonly DependencyProperty DocumentTitleTemplateSelectorProperty = - DependencyProperty.Register("DocumentTitleTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), - new FrameworkPropertyMetadata((DataTemplateSelector)null, - new PropertyChangedCallback(OnDocumentTitleTemplateSelectorChanged), - new CoerceValueCallback(CoerceDocumentTitleTemplateSelectorValue))); + /// + /// Handles changes to the AnchorablePaneControlStyle property. + /// + private static void OnAnchorablePaneControlStyleChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnAnchorablePaneControlStyleChanged( e ); + } - /// - /// Gets or sets the DocumentTitleTemplateSelector property. This dependency property - /// indicates the data template selector to use when creating the data template for the title. - /// - public DataTemplateSelector DocumentTitleTemplateSelector - { - get { return (DataTemplateSelector)GetValue(DocumentTitleTemplateSelectorProperty); } - set { SetValue(DocumentTitleTemplateSelectorProperty, value); } - } + /// + /// Provides derived classes an opportunity to handle changes to the AnchorablePaneControlStyle property. + /// + protected virtual void OnAnchorablePaneControlStyleChanged( DependencyPropertyChangedEventArgs e ) + { + } - /// - /// Handles changes to the DocumentTitleTemplateSelector property. - /// - private static void OnDocumentTitleTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnDocumentTitleTemplateSelectorChanged(e); - } + #endregion - /// - /// Provides derived classes an opportunity to handle changes to the DocumentTitleTemplateSelector property. - /// - protected virtual void OnDocumentTitleTemplateSelectorChanged(DependencyPropertyChangedEventArgs e) - { - if (e.NewValue != null) - DocumentTitleTemplate = null; - } + #region DocumentHeaderTemplate - /// - /// Coerces the DocumentTitleTemplateSelector value. - /// - private static object CoerceDocumentTitleTemplateSelectorValue(DependencyObject d, object value) - { - return value; - } + /// + /// DocumentHeaderTemplate Dependency Property + /// + public static readonly DependencyProperty DocumentHeaderTemplateProperty = + DependencyProperty.Register( "DocumentHeaderTemplate", typeof( DataTemplate ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( DataTemplate )null, + new PropertyChangedCallback( OnDocumentHeaderTemplateChanged ), + new CoerceValueCallback( CoerceDocumentHeaderTemplateValue ) ) ); - #endregion + /// + /// Gets or sets the DocumentHeaderTemplate property. This dependency property + /// indicates data template to use for document header. + /// + public DataTemplate DocumentHeaderTemplate + { + get + { + return ( DataTemplate )GetValue( DocumentHeaderTemplateProperty ); + } + set + { + SetValue( DocumentHeaderTemplateProperty, value ); + } + } - #region AnchorableTitleTemplate + /// + /// Handles changes to the DocumentHeaderTemplate property. + /// + private static void OnDocumentHeaderTemplateChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnDocumentHeaderTemplateChanged( e ); + } - /// - /// AnchorableTitleTemplate Dependency Property - /// - public static readonly DependencyProperty AnchorableTitleTemplateProperty = - DependencyProperty.Register("AnchorableTitleTemplate", typeof(DataTemplate), typeof(DockingManager), - new FrameworkPropertyMetadata((DataTemplate)null, - new PropertyChangedCallback(OnAnchorableTitleTemplateChanged), - new CoerceValueCallback(CoerceAnchorableTitleTemplateValue))); + /// + /// Provides derived classes an opportunity to handle changes to the DocumentHeaderTemplate property. + /// + protected virtual void OnDocumentHeaderTemplateChanged( DependencyPropertyChangedEventArgs e ) + { + } - /// - /// Gets or sets the AnchorableTitleTemplate property. This dependency property - /// indicates the data template to use for anchorables title. - /// - public DataTemplate AnchorableTitleTemplate - { - get { return (DataTemplate)GetValue(AnchorableTitleTemplateProperty); } - set { SetValue(AnchorableTitleTemplateProperty, value); } - } + /// + /// Coerces the DocumentHeaderTemplate value. + /// + private static object CoerceDocumentHeaderTemplateValue( DependencyObject d, object value ) + { + if( value != null && + d.GetValue( DocumentHeaderTemplateSelectorProperty ) != null ) + return null; + return value; + } - /// - /// Handles changes to the AnchorableTitleTemplate property. - /// - private static void OnAnchorableTitleTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnAnchorableTitleTemplateChanged(e); - } + #endregion - /// - /// Provides derived classes an opportunity to handle changes to the AnchorableTitleTemplate property. - /// - protected virtual void OnAnchorableTitleTemplateChanged(DependencyPropertyChangedEventArgs e) - { - } + #region DocumentHeaderTemplateSelector - /// - /// Coerces the AnchorableTitleTemplate value. - /// - private static object CoerceAnchorableTitleTemplateValue(DependencyObject d, object value) - { - if (value != null && - d.GetValue(AnchorableTitleTemplateSelectorProperty) != null) - return null; - return value; - } + /// + /// DocumentHeaderTemplateSelector Dependency Property + /// + public static readonly DependencyProperty DocumentHeaderTemplateSelectorProperty = + DependencyProperty.Register( "DocumentHeaderTemplateSelector", typeof( DataTemplateSelector ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( DataTemplateSelector )null, + new PropertyChangedCallback( OnDocumentHeaderTemplateSelectorChanged ), + new CoerceValueCallback( CoerceDocumentHeaderTemplateSelectorValue ) ) ); - #endregion + /// + /// Gets or sets the DocumentHeaderTemplateSelector property. This dependency property + /// indicates the template selector that is used when selcting the data template for the header. + /// + public DataTemplateSelector DocumentHeaderTemplateSelector + { + get + { + return ( DataTemplateSelector )GetValue( DocumentHeaderTemplateSelectorProperty ); + } + set + { + SetValue( DocumentHeaderTemplateSelectorProperty, value ); + } + } - #region AnchorableTitleTemplateSelector + /// + /// Handles changes to the DocumentHeaderTemplateSelector property. + /// + private static void OnDocumentHeaderTemplateSelectorChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnDocumentHeaderTemplateSelectorChanged( e ); + } - /// - /// AnchorableTitleTemplateSelector Dependency Property - /// - public static readonly DependencyProperty AnchorableTitleTemplateSelectorProperty = - DependencyProperty.Register("AnchorableTitleTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), - new FrameworkPropertyMetadata((DataTemplateSelector)null, - new PropertyChangedCallback(OnAnchorableTitleTemplateSelectorChanged))); + /// + /// Provides derived classes an opportunity to handle changes to the DocumentHeaderTemplateSelector property. + /// + protected virtual void OnDocumentHeaderTemplateSelectorChanged( DependencyPropertyChangedEventArgs e ) + { + if( e.NewValue != null && + DocumentHeaderTemplate != null ) + DocumentHeaderTemplate = null; - /// - /// Gets or sets the AnchorableTitleTemplateSelector property. This dependency property - /// indicates selctor to use when selecting data template for the title of anchorables. - /// - public DataTemplateSelector AnchorableTitleTemplateSelector - { - get { return (DataTemplateSelector)GetValue(AnchorableTitleTemplateSelectorProperty); } - set { SetValue(AnchorableTitleTemplateSelectorProperty, value); } - } + if( DocumentPaneMenuItemHeaderTemplateSelector == null ) + DocumentPaneMenuItemHeaderTemplateSelector = DocumentHeaderTemplateSelector; - /// - /// Handles changes to the AnchorableTitleTemplateSelector property. - /// - private static void OnAnchorableTitleTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnAnchorableTitleTemplateSelectorChanged(e); - } + } - /// - /// Provides derived classes an opportunity to handle changes to the AnchorableTitleTemplateSelector property. - /// - protected virtual void OnAnchorableTitleTemplateSelectorChanged(DependencyPropertyChangedEventArgs e) - { - if (e.NewValue != null && - AnchorableTitleTemplate != null) - AnchorableTitleTemplate = null; - } + /// + /// Coerces the DocumentHeaderTemplateSelector value. + /// + private static object CoerceDocumentHeaderTemplateSelectorValue( DependencyObject d, object value ) + { + return value; + } - #endregion + #endregion - #region AnchorableHeaderTemplate + #region DocumentTitleTemplate - /// - /// AnchorableHeaderTemplate Dependency Property - /// - public static readonly DependencyProperty AnchorableHeaderTemplateProperty = - DependencyProperty.Register("AnchorableHeaderTemplate", typeof(DataTemplate), typeof(DockingManager), - new FrameworkPropertyMetadata((DataTemplate)null, - new PropertyChangedCallback(OnAnchorableHeaderTemplateChanged), - new CoerceValueCallback(CoerceAnchorableHeaderTemplateValue))); + /// + /// DocumentTitleTemplate Dependency Property + /// + public static readonly DependencyProperty DocumentTitleTemplateProperty = + DependencyProperty.Register( "DocumentTitleTemplate", typeof( DataTemplate ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( DataTemplate )null, + new PropertyChangedCallback( OnDocumentTitleTemplateChanged ), + new CoerceValueCallback( CoerceDocumentTitleTemplateValue ) ) ); - /// - /// Gets or sets the AnchorableHeaderTemplate property. This dependency property - /// indicates the data template to use for anchorable templates. - /// - public DataTemplate AnchorableHeaderTemplate - { - get { return (DataTemplate)GetValue(AnchorableHeaderTemplateProperty); } - set { SetValue(AnchorableHeaderTemplateProperty, value); } - } + /// + /// Gets or sets the DocumentTitleTemplate property. This dependency property + /// indicates the datatemplate to use when creating the title for a document. + /// + public DataTemplate DocumentTitleTemplate + { + get + { + return ( DataTemplate )GetValue( DocumentTitleTemplateProperty ); + } + set + { + SetValue( DocumentTitleTemplateProperty, value ); + } + } - /// - /// Handles changes to the AnchorableHeaderTemplate property. - /// - private static void OnAnchorableHeaderTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnAnchorableHeaderTemplateChanged(e); - } + /// + /// Handles changes to the DocumentTitleTemplate property. + /// + private static void OnDocumentTitleTemplateChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnDocumentTitleTemplateChanged( e ); + } - /// - /// Provides derived classes an opportunity to handle changes to the AnchorableHeaderTemplate property. - /// - protected virtual void OnAnchorableHeaderTemplateChanged(DependencyPropertyChangedEventArgs e) - { - } + /// + /// Provides derived classes an opportunity to handle changes to the DocumentTitleTemplate property. + /// + protected virtual void OnDocumentTitleTemplateChanged( DependencyPropertyChangedEventArgs e ) + { + } - /// - /// Coerces the AnchorableHeaderTemplate value. - /// - private static object CoerceAnchorableHeaderTemplateValue(DependencyObject d, object value) - { - if (value != null && - d.GetValue(AnchorableHeaderTemplateSelectorProperty) != null) - return null; + /// + /// Coerces the DocumentTitleTemplate value. + /// + private static object CoerceDocumentTitleTemplateValue( DependencyObject d, object value ) + { + if( value != null && + d.GetValue( DocumentTitleTemplateSelectorProperty ) != null ) + return null; - return value; - } + return value; + } - #endregion + #endregion - #region AnchorableHeaderTemplateSelector + #region DocumentTitleTemplateSelector - /// - /// AnchorableHeaderTemplateSelector Dependency Property - /// - public static readonly DependencyProperty AnchorableHeaderTemplateSelectorProperty = - DependencyProperty.Register("AnchorableHeaderTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), - new FrameworkPropertyMetadata((DataTemplateSelector)null, - new PropertyChangedCallback(OnAnchorableHeaderTemplateSelectorChanged))); + /// + /// DocumentTitleTemplateSelector Dependency Property + /// + public static readonly DependencyProperty DocumentTitleTemplateSelectorProperty = + DependencyProperty.Register( "DocumentTitleTemplateSelector", typeof( DataTemplateSelector ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( DataTemplateSelector )null, + new PropertyChangedCallback( OnDocumentTitleTemplateSelectorChanged ), + new CoerceValueCallback( CoerceDocumentTitleTemplateSelectorValue ) ) ); - /// - /// Gets or sets the AnchorableHeaderTemplateSelector property. This dependency property - /// indicates the selector to use when selecting the data template for anchorable headers. - /// - public DataTemplateSelector AnchorableHeaderTemplateSelector - { - get { return (DataTemplateSelector)GetValue(AnchorableHeaderTemplateSelectorProperty); } - set { SetValue(AnchorableHeaderTemplateSelectorProperty, value); } - } + /// + /// Gets or sets the DocumentTitleTemplateSelector property. This dependency property + /// indicates the data template selector to use when creating the data template for the title. + /// + public DataTemplateSelector DocumentTitleTemplateSelector + { + get + { + return ( DataTemplateSelector )GetValue( DocumentTitleTemplateSelectorProperty ); + } + set + { + SetValue( DocumentTitleTemplateSelectorProperty, value ); + } + } - /// - /// Handles changes to the AnchorableHeaderTemplateSelector property. - /// - private static void OnAnchorableHeaderTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnAnchorableHeaderTemplateSelectorChanged(e); - } + /// + /// Handles changes to the DocumentTitleTemplateSelector property. + /// + private static void OnDocumentTitleTemplateSelectorChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnDocumentTitleTemplateSelectorChanged( e ); + } - /// - /// Provides derived classes an opportunity to handle changes to the AnchorableHeaderTemplateSelector property. - /// - protected virtual void OnAnchorableHeaderTemplateSelectorChanged(DependencyPropertyChangedEventArgs e) - { - if (e.NewValue != null) - AnchorableHeaderTemplate = null; - } + /// + /// Provides derived classes an opportunity to handle changes to the DocumentTitleTemplateSelector property. + /// + protected virtual void OnDocumentTitleTemplateSelectorChanged( DependencyPropertyChangedEventArgs e ) + { + if( e.NewValue != null ) + DocumentTitleTemplate = null; + } - #endregion + /// + /// Coerces the DocumentTitleTemplateSelector value. + /// + private static object CoerceDocumentTitleTemplateSelectorValue( DependencyObject d, object value ) + { + return value; + } - #region LayoutRootPanel + #endregion - /// - /// LayoutRootPanel Dependency Property - /// - public static readonly DependencyProperty LayoutRootPanelProperty = - DependencyProperty.Register("LayoutRootPanel", typeof(LayoutPanelControl), typeof(DockingManager), - new FrameworkPropertyMetadata((LayoutPanelControl)null, - new PropertyChangedCallback(OnLayoutRootPanelChanged))); + #region AnchorableTitleTemplate - /// - /// Gets or sets the LayoutRootPanel property. This dependency property - /// indicates the layout panel control which is attached to the Layout.Root property. - /// - public LayoutPanelControl LayoutRootPanel - { - get { return (LayoutPanelControl)GetValue(LayoutRootPanelProperty); } - set { SetValue(LayoutRootPanelProperty, value); } - } + /// + /// AnchorableTitleTemplate Dependency Property + /// + public static readonly DependencyProperty AnchorableTitleTemplateProperty = + DependencyProperty.Register( "AnchorableTitleTemplate", typeof( DataTemplate ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( DataTemplate )null, + new PropertyChangedCallback( OnAnchorableTitleTemplateChanged ), + new CoerceValueCallback( CoerceAnchorableTitleTemplateValue ) ) ); - /// - /// Handles changes to the LayoutRootPanel property. - /// - private static void OnLayoutRootPanelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnLayoutRootPanelChanged(e); - } + /// + /// Gets or sets the AnchorableTitleTemplate property. This dependency property + /// indicates the data template to use for anchorables title. + /// + public DataTemplate AnchorableTitleTemplate + { + get + { + return ( DataTemplate )GetValue( AnchorableTitleTemplateProperty ); + } + set + { + SetValue( AnchorableTitleTemplateProperty, value ); + } + } - /// - /// Provides derived classes an opportunity to handle changes to the LayoutRootPanel property. - /// - protected virtual void OnLayoutRootPanelChanged(DependencyPropertyChangedEventArgs e) - { - if (e.OldValue != null) - InternalRemoveLogicalChild(e.OldValue); - if (e.NewValue != null) - InternalAddLogicalChild(e.NewValue); - } + /// + /// Handles changes to the AnchorableTitleTemplate property. + /// + private static void OnAnchorableTitleTemplateChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnAnchorableTitleTemplateChanged( e ); + } - #endregion + /// + /// Provides derived classes an opportunity to handle changes to the AnchorableTitleTemplate property. + /// + protected virtual void OnAnchorableTitleTemplateChanged( DependencyPropertyChangedEventArgs e ) + { + } - #region RightSidePanel + /// + /// Coerces the AnchorableTitleTemplate value. + /// + private static object CoerceAnchorableTitleTemplateValue( DependencyObject d, object value ) + { + if( value != null && + d.GetValue( AnchorableTitleTemplateSelectorProperty ) != null ) + return null; + return value; + } - /// - /// RightSidePanel Dependency Property - /// - public static readonly DependencyProperty RightSidePanelProperty = - DependencyProperty.Register("RightSidePanel", typeof(LayoutAnchorSideControl), typeof(DockingManager), - new FrameworkPropertyMetadata((LayoutAnchorSideControl)null, - new PropertyChangedCallback(OnRightSidePanelChanged))); + #endregion - /// - /// Gets or sets the RightSidePanel property. This dependency property - /// indicates right side anchor panel. - /// - public LayoutAnchorSideControl RightSidePanel - { - get { return (LayoutAnchorSideControl)GetValue(RightSidePanelProperty); } - set { SetValue(RightSidePanelProperty, value); } - } + #region AnchorableTitleTemplateSelector - /// - /// Handles changes to the RightSidePanel property. - /// - private static void OnRightSidePanelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnRightSidePanelChanged(e); - } + /// + /// AnchorableTitleTemplateSelector Dependency Property + /// + public static readonly DependencyProperty AnchorableTitleTemplateSelectorProperty = + DependencyProperty.Register( "AnchorableTitleTemplateSelector", typeof( DataTemplateSelector ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( DataTemplateSelector )null, + new PropertyChangedCallback( OnAnchorableTitleTemplateSelectorChanged ) ) ); - /// - /// Provides derived classes an opportunity to handle changes to the RightSidePanel property. - /// - protected virtual void OnRightSidePanelChanged(DependencyPropertyChangedEventArgs e) - { - if (e.OldValue != null) - InternalRemoveLogicalChild(e.OldValue); - if (e.NewValue != null) - InternalAddLogicalChild(e.NewValue); - } + /// + /// Gets or sets the AnchorableTitleTemplateSelector property. This dependency property + /// indicates selctor to use when selecting data template for the title of anchorables. + /// + public DataTemplateSelector AnchorableTitleTemplateSelector + { + get + { + return ( DataTemplateSelector )GetValue( AnchorableTitleTemplateSelectorProperty ); + } + set + { + SetValue( AnchorableTitleTemplateSelectorProperty, value ); + } + } + + /// + /// Handles changes to the AnchorableTitleTemplateSelector property. + /// + private static void OnAnchorableTitleTemplateSelectorChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnAnchorableTitleTemplateSelectorChanged( e ); + } - #endregion + /// + /// Provides derived classes an opportunity to handle changes to the AnchorableTitleTemplateSelector property. + /// + protected virtual void OnAnchorableTitleTemplateSelectorChanged( DependencyPropertyChangedEventArgs e ) + { + if( e.NewValue != null && + AnchorableTitleTemplate != null ) + AnchorableTitleTemplate = null; + } - #region LeftSidePanel + #endregion - /// - /// LeftSidePanel Dependency Property - /// - public static readonly DependencyProperty LeftSidePanelProperty = - DependencyProperty.Register("LeftSidePanel", typeof(LayoutAnchorSideControl), typeof(DockingManager), - new FrameworkPropertyMetadata((LayoutAnchorSideControl)null, - new PropertyChangedCallback(OnLeftSidePanelChanged))); + #region AnchorableHeaderTemplate - /// - /// Gets or sets the LeftSidePanel property. This dependency property - /// indicates the left side panel control. - /// - public LayoutAnchorSideControl LeftSidePanel - { - get { return (LayoutAnchorSideControl)GetValue(LeftSidePanelProperty); } - set { SetValue(LeftSidePanelProperty, value); } - } + /// + /// AnchorableHeaderTemplate Dependency Property + /// + public static readonly DependencyProperty AnchorableHeaderTemplateProperty = + DependencyProperty.Register( "AnchorableHeaderTemplate", typeof( DataTemplate ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( DataTemplate )null, + new PropertyChangedCallback( OnAnchorableHeaderTemplateChanged ), + new CoerceValueCallback( CoerceAnchorableHeaderTemplateValue ) ) ); - /// - /// Handles changes to the LeftSidePanel property. - /// - private static void OnLeftSidePanelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnLeftSidePanelChanged(e); - } + /// + /// Gets or sets the AnchorableHeaderTemplate property. This dependency property + /// indicates the data template to use for anchorable templates. + /// + public DataTemplate AnchorableHeaderTemplate + { + get + { + return ( DataTemplate )GetValue( AnchorableHeaderTemplateProperty ); + } + set + { + SetValue( AnchorableHeaderTemplateProperty, value ); + } + } - /// - /// Provides derived classes an opportunity to handle changes to the LeftSidePanel property. - /// - protected virtual void OnLeftSidePanelChanged(DependencyPropertyChangedEventArgs e) - { - if (e.OldValue != null) - InternalRemoveLogicalChild(e.OldValue); - if (e.NewValue != null) - InternalAddLogicalChild(e.NewValue); - } + /// + /// Handles changes to the AnchorableHeaderTemplate property. + /// + private static void OnAnchorableHeaderTemplateChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnAnchorableHeaderTemplateChanged( e ); + } - #endregion + /// + /// Provides derived classes an opportunity to handle changes to the AnchorableHeaderTemplate property. + /// + protected virtual void OnAnchorableHeaderTemplateChanged( DependencyPropertyChangedEventArgs e ) + { + } - #region TopSidePanel + /// + /// Coerces the AnchorableHeaderTemplate value. + /// + private static object CoerceAnchorableHeaderTemplateValue( DependencyObject d, object value ) + { + if( value != null && + d.GetValue( AnchorableHeaderTemplateSelectorProperty ) != null ) + return null; - /// - /// TopSidePanel Dependency Property - /// - public static readonly DependencyProperty TopSidePanelProperty = - DependencyProperty.Register("TopSidePanel", typeof(LayoutAnchorSideControl), typeof(DockingManager), - new FrameworkPropertyMetadata((LayoutAnchorSideControl)null, - new PropertyChangedCallback(OnTopSidePanelChanged))); + return value; + } - /// - /// Gets or sets the TopSidePanel property. This dependency property - /// indicates top side control panel. - /// - public LayoutAnchorSideControl TopSidePanel - { - get { return (LayoutAnchorSideControl)GetValue(TopSidePanelProperty); } - set { SetValue(TopSidePanelProperty, value); } - } + #endregion - /// - /// Handles changes to the TopSidePanel property. - /// - private static void OnTopSidePanelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnTopSidePanelChanged(e); - } + #region AnchorableHeaderTemplateSelector - /// - /// Provides derived classes an opportunity to handle changes to the TopSidePanel property. - /// - protected virtual void OnTopSidePanelChanged(DependencyPropertyChangedEventArgs e) - { - if (e.OldValue != null) - InternalRemoveLogicalChild(e.OldValue); - if (e.NewValue != null) - InternalAddLogicalChild(e.NewValue); - } + /// + /// AnchorableHeaderTemplateSelector Dependency Property + /// + public static readonly DependencyProperty AnchorableHeaderTemplateSelectorProperty = + DependencyProperty.Register( "AnchorableHeaderTemplateSelector", typeof( DataTemplateSelector ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( DataTemplateSelector )null, + new PropertyChangedCallback( OnAnchorableHeaderTemplateSelectorChanged ) ) ); - #endregion + /// + /// Gets or sets the AnchorableHeaderTemplateSelector property. This dependency property + /// indicates the selector to use when selecting the data template for anchorable headers. + /// + public DataTemplateSelector AnchorableHeaderTemplateSelector + { + get + { + return ( DataTemplateSelector )GetValue( AnchorableHeaderTemplateSelectorProperty ); + } + set + { + SetValue( AnchorableHeaderTemplateSelectorProperty, value ); + } + } - #region BottomSidePanel + /// + /// Handles changes to the AnchorableHeaderTemplateSelector property. + /// + private static void OnAnchorableHeaderTemplateSelectorChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnAnchorableHeaderTemplateSelectorChanged( e ); + } - /// - /// BottomSidePanel Dependency Property - /// - public static readonly DependencyProperty BottomSidePanelProperty = - DependencyProperty.Register("BottomSidePanel", typeof(LayoutAnchorSideControl), typeof(DockingManager), - new FrameworkPropertyMetadata((LayoutAnchorSideControl)null, - new PropertyChangedCallback(OnBottomSidePanelChanged))); + /// + /// Provides derived classes an opportunity to handle changes to the AnchorableHeaderTemplateSelector property. + /// + protected virtual void OnAnchorableHeaderTemplateSelectorChanged( DependencyPropertyChangedEventArgs e ) + { + if( e.NewValue != null ) + AnchorableHeaderTemplate = null; + } - /// - /// Gets or sets the BottomSidePanel property. This dependency property - /// indicates bottom side panel control. - /// - public LayoutAnchorSideControl BottomSidePanel - { - get { return (LayoutAnchorSideControl)GetValue(BottomSidePanelProperty); } - set { SetValue(BottomSidePanelProperty, value); } - } + #endregion - /// - /// Handles changes to the BottomSidePanel property. - /// - private static void OnBottomSidePanelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnBottomSidePanelChanged(e); - } + #region LayoutRootPanel - /// - /// Provides derived classes an opportunity to handle changes to the BottomSidePanel property. - /// - protected virtual void OnBottomSidePanelChanged(DependencyPropertyChangedEventArgs e) - { - if (e.OldValue != null) - InternalRemoveLogicalChild(e.OldValue); - if (e.NewValue != null) - InternalAddLogicalChild(e.NewValue); - } + /// + /// LayoutRootPanel Dependency Property + /// + public static readonly DependencyProperty LayoutRootPanelProperty = + DependencyProperty.Register( "LayoutRootPanel", typeof( LayoutPanelControl ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( LayoutPanelControl )null, + new PropertyChangedCallback( OnLayoutRootPanelChanged ) ) ); - #endregion + /// + /// Gets or sets the LayoutRootPanel property. This dependency property + /// indicates the layout panel control which is attached to the Layout.Root property. + /// + public LayoutPanelControl LayoutRootPanel + { + get + { + return ( LayoutPanelControl )GetValue( LayoutRootPanelProperty ); + } + set + { + SetValue( LayoutRootPanelProperty, value ); + } + } - #region LogicalChildren + /// + /// Handles changes to the LayoutRootPanel property. + /// + private static void OnLayoutRootPanelChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnLayoutRootPanelChanged( e ); + } - List _logicalChildren = new List(); + /// + /// Provides derived classes an opportunity to handle changes to the LayoutRootPanel property. + /// + protected virtual void OnLayoutRootPanelChanged( DependencyPropertyChangedEventArgs e ) + { + if( e.OldValue != null ) + InternalRemoveLogicalChild( e.OldValue ); + if( e.NewValue != null ) + InternalAddLogicalChild( e.NewValue ); + } - protected override System.Collections.IEnumerator LogicalChildren - { - get - { - return _logicalChildren.Select(ch => ch.GetValueOrDefault()).GetEnumerator(); - } - } + #endregion - public System.Collections.IEnumerator LogicalChildrenPublic + #region RightSidePanel + + /// + /// RightSidePanel Dependency Property + /// + public static readonly DependencyProperty RightSidePanelProperty = + DependencyProperty.Register( "RightSidePanel", typeof( LayoutAnchorSideControl ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( LayoutAnchorSideControl )null, + new PropertyChangedCallback( OnRightSidePanelChanged ) ) ); + + /// + /// Gets or sets the RightSidePanel property. This dependency property + /// indicates right side anchor panel. + /// + public LayoutAnchorSideControl RightSidePanel { get { - return this.LogicalChildren; + return ( LayoutAnchorSideControl )GetValue( RightSidePanelProperty ); + } + set + { + SetValue( RightSidePanelProperty, value ); } } + /// + /// Handles changes to the RightSidePanel property. + /// + private static void OnRightSidePanelChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnRightSidePanelChanged( e ); + } - internal void InternalAddLogicalChild(object element) - { -#if DEBUG - if (_logicalChildren.Select(ch => ch.GetValueOrDefault()).Contains(element)) - new InvalidOperationException(); -#endif - if (_logicalChildren.Select(ch => ch.GetValueOrDefault()).Contains(element)) - return; + /// + /// Provides derived classes an opportunity to handle changes to the RightSidePanel property. + /// + protected virtual void OnRightSidePanelChanged( DependencyPropertyChangedEventArgs e ) + { + if( e.OldValue != null ) + InternalRemoveLogicalChild( e.OldValue ); + if( e.NewValue != null ) + InternalAddLogicalChild( e.NewValue ); + } - _logicalChildren.Add(new WeakReference(element)); - AddLogicalChild(element); - } + #endregion - internal void InternalRemoveLogicalChild(object element) - { - var wrToRemove = _logicalChildren.FirstOrDefault(ch => ch.GetValueOrDefault() == element); - if (wrToRemove != null) - _logicalChildren.Remove(wrToRemove); - RemoveLogicalChild(element); - } + #region LeftSidePanel - void ClearLogicalChildrenList() - { - foreach (var child in _logicalChildren.Select(ch => ch.GetValueOrDefault()).ToArray()) - RemoveLogicalChild(child); - _logicalChildren.Clear(); - } + /// + /// LeftSidePanel Dependency Property + /// + public static readonly DependencyProperty LeftSidePanelProperty = + DependencyProperty.Register( "LeftSidePanel", typeof( LayoutAnchorSideControl ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( LayoutAnchorSideControl )null, + new PropertyChangedCallback( OnLeftSidePanelChanged ) ) ); - #endregion + /// + /// Gets or sets the LeftSidePanel property. This dependency property + /// indicates the left side panel control. + /// + public LayoutAnchorSideControl LeftSidePanel + { + get + { + return ( LayoutAnchorSideControl )GetValue( LeftSidePanelProperty ); + } + set + { + SetValue( LeftSidePanelProperty, value ); + } + } - #region AutoHide window - internal void ShowAutoHideWindow(LayoutAnchorControl anchor) - { - _autoHideWindowManager.ShowAutoHideWindow(anchor); - //if (_autohideArea == null) - // return; + /// + /// Handles changes to the LeftSidePanel property. + /// + private static void OnLeftSidePanelChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnLeftSidePanelChanged( e ); + } - //if (AutoHideWindow != null && AutoHideWindow.Model == anchor.Model) - // return; + /// + /// Provides derived classes an opportunity to handle changes to the LeftSidePanel property. + /// + protected virtual void OnLeftSidePanelChanged( DependencyPropertyChangedEventArgs e ) + { + if( e.OldValue != null ) + InternalRemoveLogicalChild( e.OldValue ); + if( e.NewValue != null ) + InternalAddLogicalChild( e.NewValue ); + } - //Trace.WriteLine("ShowAutoHideWindow()"); + #endregion - //_currentAutohiddenAnchor = new WeakReference(anchor); + #region TopSidePanel - //HideAutoHideWindow(anchor); + /// + /// TopSidePanel Dependency Property + /// + public static readonly DependencyProperty TopSidePanelProperty = + DependencyProperty.Register( "TopSidePanel", typeof( LayoutAnchorSideControl ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( LayoutAnchorSideControl )null, + new PropertyChangedCallback( OnTopSidePanelChanged ) ) ); - //SetAutoHideWindow(new LayoutAutoHideWindowControl(anchor)); - //AutoHideWindow.Show(); - } + /// + /// Gets or sets the TopSidePanel property. This dependency property + /// indicates top side control panel. + /// + public LayoutAnchorSideControl TopSidePanel + { + get + { + return ( LayoutAnchorSideControl )GetValue( TopSidePanelProperty ); + } + set + { + SetValue( TopSidePanelProperty, value ); + } + } - internal void HideAutoHideWindow(LayoutAnchorControl anchor) - { - _autoHideWindowManager.HideAutoWindow(anchor); - } + /// + /// Handles changes to the TopSidePanel property. + /// + private static void OnTopSidePanelChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnTopSidePanelChanged( e ); + } + /// + /// Provides derived classes an opportunity to handle changes to the TopSidePanel property. + /// + protected virtual void OnTopSidePanelChanged( DependencyPropertyChangedEventArgs e ) + { + if( e.OldValue != null ) + InternalRemoveLogicalChild( e.OldValue ); + if( e.NewValue != null ) + InternalAddLogicalChild( e.NewValue ); + } - void SetupAutoHideWindow() - { - _autohideArea = GetTemplateChild("PART_AutoHideArea") as FrameworkElement; + #endregion - if (_autoHideWindowManager != null) - _autoHideWindowManager.HideAutoWindow(); - else - _autoHideWindowManager = new AutoHideWindowManager(this); + #region BottomSidePanel - if (AutoHideWindow != null) - AutoHideWindow.Dispose(); + /// + /// BottomSidePanel Dependency Property + /// + public static readonly DependencyProperty BottomSidePanelProperty = + DependencyProperty.Register( "BottomSidePanel", typeof( LayoutAnchorSideControl ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( LayoutAnchorSideControl )null, + new PropertyChangedCallback( OnBottomSidePanelChanged ) ) ); - SetAutoHideWindow(new LayoutAutoHideWindowControl()); - } + /// + /// Gets or sets the BottomSidePanel property. This dependency property + /// indicates bottom side panel control. + /// + public LayoutAnchorSideControl BottomSidePanel + { + get + { + return ( LayoutAnchorSideControl )GetValue( BottomSidePanelProperty ); + } + set + { + SetValue( BottomSidePanelProperty, value ); + } + } - AutoHideWindowManager _autoHideWindowManager; + /// + /// Handles changes to the BottomSidePanel property. + /// + private static void OnBottomSidePanelChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnBottomSidePanelChanged( e ); + } - FrameworkElement _autohideArea; - internal FrameworkElement GetAutoHideAreaElement() - { - return _autohideArea; - } + /// + /// Provides derived classes an opportunity to handle changes to the BottomSidePanel property. + /// + protected virtual void OnBottomSidePanelChanged( DependencyPropertyChangedEventArgs e ) + { + if( e.OldValue != null ) + InternalRemoveLogicalChild( e.OldValue ); + if( e.NewValue != null ) + InternalAddLogicalChild( e.NewValue ); + } - #region AutoHideWindow + #endregion - /// - /// AutoHideWindow Read-Only Dependency Property - /// - private static readonly DependencyPropertyKey AutoHideWindowPropertyKey - = DependencyProperty.RegisterReadOnly("AutoHideWindow", typeof(LayoutAutoHideWindowControl), typeof(DockingManager), - new FrameworkPropertyMetadata((LayoutAutoHideWindowControl)null, - new PropertyChangedCallback(OnAutoHideWindowChanged))); + #region LogicalChildren - public static readonly DependencyProperty AutoHideWindowProperty - = AutoHideWindowPropertyKey.DependencyProperty; + List _logicalChildren = new List(); - /// - /// Gets the AutoHideWindow property. This dependency property - /// indicates the currently shown autohide window. - /// - public LayoutAutoHideWindowControl AutoHideWindow - { - get { return (LayoutAutoHideWindowControl)GetValue(AutoHideWindowProperty); } - } + protected override System.Collections.IEnumerator LogicalChildren + { + get + { + return _logicalChildren.Select( ch => ch.GetValueOrDefault() ).GetEnumerator(); + } + } - /// - /// Provides a secure method for setting the AutoHideWindow property. - /// This dependency property indicates the currently shown autohide window. - /// - /// The new value for the property. - protected void SetAutoHideWindow(LayoutAutoHideWindowControl value) - { - SetValue(AutoHideWindowPropertyKey, value); - } + public System.Collections.IEnumerator LogicalChildrenPublic + { + get + { + return this.LogicalChildren; + } + } - /// - /// Handles changes to the AutoHideWindow property. - /// - private static void OnAutoHideWindowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnAutoHideWindowChanged(e); - } - /// - /// Provides derived classes an opportunity to handle changes to the AutoHideWindow property. - /// - protected virtual void OnAutoHideWindowChanged(DependencyPropertyChangedEventArgs e) - { - if (e.OldValue != null) - InternalRemoveLogicalChild(e.OldValue); - if (e.NewValue != null) - InternalAddLogicalChild(e.NewValue); + internal void InternalAddLogicalChild( object element ) + { +#if DEBUG + if( _logicalChildren.Select( ch => ch.GetValueOrDefault() ).Contains( element ) ) + new InvalidOperationException(); +#endif + if( _logicalChildren.Select( ch => ch.GetValueOrDefault() ).Contains( element ) ) + return; - } + _logicalChildren.Add( new WeakReference( element ) ); + AddLogicalChild( element ); + } + + internal void InternalRemoveLogicalChild( object element ) + { + var wrToRemove = _logicalChildren.FirstOrDefault( ch => ch.GetValueOrDefault() == element ); + if( wrToRemove != null ) + _logicalChildren.Remove( wrToRemove ); + RemoveLogicalChild( element ); + } + + void ClearLogicalChildrenList() + { + foreach( var child in _logicalChildren.Select( ch => ch.GetValueOrDefault() ).ToArray() ) + RemoveLogicalChild( child ); + _logicalChildren.Clear(); + } - #endregion - - - - #endregion - // #region AutoHide window - //WeakReference _currentAutohiddenAnchor = null; - //internal void ShowAutoHideWindow(LayoutAnchorControl anchor) - //{ - // if (_autohideArea == null) - // return; - - // if (AutoHideWindow != null && AutoHideWindow.Model == anchor.Model) - // return; - - // Trace.WriteLine("ShowAutoHideWindow()"); - - // _currentAutohiddenAnchor = new WeakReference(anchor); - - // HideAutoHideWindow(anchor); - - // SetAutoHideWindow(new LayoutAutoHideWindowControl(anchor)); - //} - - //internal void HideAutoHideWindow(LayoutAnchorControl anchor) - //{ - // if (AutoHideWindow != null) - // { - // if (anchor == _currentAutohiddenAnchor.GetValueOrDefault()) - // { - // Trace.WriteLine("AutoHideWindow()"); - // AutoHideWindow.Dispose(); - // SetAutoHideWindow(null); - // } - // } - //} - - //FrameworkElement _autohideArea; - //internal FrameworkElement GetAutoHideAreaElement() - //{ - // return _autohideArea; - //} - - //void SetupAutoHideArea() - //{ - // _autohideArea = GetTemplateChild("PART_AutoHideArea") as FrameworkElement; - //} - - // #region AutoHideWindow - - ///// - ///// AutoHideWindow Read-Only Dependency Property - ///// - //private static readonly DependencyPropertyKey AutoHideWindowPropertyKey - // = DependencyProperty.RegisterReadOnly("AutoHideWindow", typeof(LayoutAutoHideWindowControl), typeof(DockingManager), - // new FrameworkPropertyMetadata((LayoutAutoHideWindowControl)null, - // new PropertyChangedCallback(OnAutoHideWindowChanged))); - - //public static readonly DependencyProperty AutoHideWindowProperty - // = AutoHideWindowPropertyKey.DependencyProperty; - - ///// - ///// Gets the AutoHideWindow property. This dependency property - ///// indicates the currently shown autohide window. - ///// - //public LayoutAutoHideWindowControl AutoHideWindow - //{ - // get { return (LayoutAutoHideWindowControl)GetValue(AutoHideWindowProperty); } - //} - - ///// - ///// Provides a secure method for setting the AutoHideWindow property. - ///// This dependency property indicates the currently shown autohide window. - ///// - ///// The new value for the property. - //protected void SetAutoHideWindow(LayoutAutoHideWindowControl value) - //{ - // SetValue(AutoHideWindowPropertyKey, value); - //} - - ///// - ///// Handles changes to the AutoHideWindow property. - ///// - //private static void OnAutoHideWindowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - //{ - // ((DockingManager)d).OnAutoHideWindowChanged(e); - //} - - ///// - ///// Provides derived classes an opportunity to handle changes to the AutoHideWindow property. - ///// - //protected virtual void OnAutoHideWindowChanged(DependencyPropertyChangedEventArgs e) - //{ - // if (e.OldValue != null) - // ((ILogicalChildrenContainer)this).InternalRemoveLogicalChild(e.OldValue); - // if (e.NewValue != null) - // ((ILogicalChildrenContainer)this).InternalAddLogicalChild(e.NewValue); - //} - - // #endregion - - - - // #endregion - - #region Floating Windows - List _fwList = new List(); - - internal void StartDraggingFloatingWindowForContent(LayoutContent contentModel, bool startDrag = true) - { - if (!contentModel.CanFloat) - return; - var contentModelAsAnchorable = contentModel as LayoutAnchorable; - if (contentModelAsAnchorable != null && - contentModelAsAnchorable.IsAutoHidden) - contentModelAsAnchorable.ToggleAutoHide(); - - var parentPane = contentModel.Parent as ILayoutPane; - var parentPaneAsPositionableElement = contentModel.Parent as ILayoutPositionableElement; - var parentPaneAsWithActualSize = contentModel.Parent as ILayoutPositionableElementWithActualSize; - var contentModelParentChildrenIndex = parentPane.Children.ToList().IndexOf(contentModel); - - if (contentModel.FindParent() == null) - { - ((ILayoutPreviousContainer)contentModel).PreviousContainer = parentPane; - contentModel.PreviousContainerIndex = contentModelParentChildrenIndex; - } + #endregion - parentPane.RemoveChildAt(contentModelParentChildrenIndex); + #region AutoHide window + internal void ShowAutoHideWindow( LayoutAnchorControl anchor ) + { + _autoHideWindowManager.ShowAutoHideWindow( anchor ); + //if (_autohideArea == null) + // return; - double fwWidth = contentModel.FloatingWidth; - double fwHeight = contentModel.FloatingHeight; + //if (AutoHideWindow != null && AutoHideWindow.Model == anchor.Model) + // return; - if (fwWidth == 0.0) - fwWidth = parentPaneAsPositionableElement.FloatingWidth; - if (fwHeight == 0.0) - fwHeight = parentPaneAsPositionableElement.FloatingHeight; + //Trace.WriteLine("ShowAutoHideWindow()"); - if (fwWidth == 0.0) - fwWidth = parentPaneAsWithActualSize.ActualWidth; - if (fwHeight == 0.0) - fwHeight = parentPaneAsWithActualSize.ActualHeight; + //_currentAutohiddenAnchor = new WeakReference(anchor); - LayoutFloatingWindow fw; - LayoutFloatingWindowControl fwc; - if (contentModel is LayoutAnchorable) - { - var anchorableContent = contentModel as LayoutAnchorable; - fw = new LayoutAnchorableFloatingWindow() - { - RootPanel = new LayoutAnchorablePaneGroup( - new LayoutAnchorablePane(anchorableContent) - { - DockWidth = parentPaneAsPositionableElement.DockWidth, - DockHeight = parentPaneAsPositionableElement.DockHeight, - DockMinHeight = parentPaneAsPositionableElement.DockMinHeight, - DockMinWidth = parentPaneAsPositionableElement.DockMinWidth, - FloatingLeft = parentPaneAsPositionableElement.FloatingLeft, - FloatingTop = parentPaneAsPositionableElement.FloatingTop, - FloatingWidth = parentPaneAsPositionableElement.FloatingWidth, - FloatingHeight = parentPaneAsPositionableElement.FloatingHeight, - }) - }; - - Layout.FloatingWindows.Add(fw); - - fwc = new LayoutAnchorableFloatingWindowControl( - fw as LayoutAnchorableFloatingWindow) - { - Width = fwWidth, - Height = fwHeight, - Left = contentModel.FloatingLeft, - Top = contentModel.FloatingTop - }; - } - else - { - var anchorableDocument = contentModel as LayoutDocument; - fw = new LayoutDocumentFloatingWindow() - { - RootDocument = anchorableDocument - }; + //HideAutoHideWindow(anchor); - Layout.FloatingWindows.Add(fw); + //SetAutoHideWindow(new LayoutAutoHideWindowControl(anchor)); + //AutoHideWindow.Show(); + } - fwc = new LayoutDocumentFloatingWindowControl( - fw as LayoutDocumentFloatingWindow) - { - Width = fwWidth, - Height = fwHeight, - Left = contentModel.FloatingLeft, - Top = contentModel.FloatingTop - }; - } + internal void HideAutoHideWindow( LayoutAnchorControl anchor ) + { + _autoHideWindowManager.HideAutoWindow( anchor ); + } - //fwc.Owner = Window.GetWindow(this); - //fwc.SetParentToMainWindowOf(this); + void SetupAutoHideWindow() + { + if( _autoHideWindowManager != null ) + _autoHideWindowManager.HideAutoWindow(); + else + _autoHideWindowManager = new AutoHideWindowManager( this ); + if( AutoHideWindow != null ) + AutoHideWindow.Dispose(); - _fwList.Add(fwc); + SetAutoHideWindow( new LayoutAutoHideWindowControl() ); + } - Layout.CollectGarbage(); + AutoHideWindowManager _autoHideWindowManager; - UpdateLayout(); + FrameworkElement _autohideArea; + internal FrameworkElement GetAutoHideAreaElement() + { + return _autohideArea; + } - Dispatcher.BeginInvoke(new Action(() => - { - if (startDrag) - fwc.AttachDrag(); - fwc.Show(); - }), DispatcherPriority.Send); - } + #region AutoHideWindow - internal void StartDraggingFloatingWindowForPane(LayoutAnchorablePane paneModel) - { - if (paneModel.Children.Any(c => !c.CanFloat)) - return; - var paneAsPositionableElement = paneModel as ILayoutPositionableElement; - var paneAsWithActualSize = paneModel as ILayoutPositionableElementWithActualSize; + /// + /// AutoHideWindow Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey AutoHideWindowPropertyKey + = DependencyProperty.RegisterReadOnly( "AutoHideWindow", typeof( LayoutAutoHideWindowControl ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( LayoutAutoHideWindowControl )null, + new PropertyChangedCallback( OnAutoHideWindowChanged ) ) ); - double fwWidth = paneAsPositionableElement.FloatingWidth; - double fwHeight = paneAsPositionableElement.FloatingHeight; - double fwLeft = paneAsPositionableElement.FloatingLeft; - double fwTop = paneAsPositionableElement.FloatingTop; + public static readonly DependencyProperty AutoHideWindowProperty + = AutoHideWindowPropertyKey.DependencyProperty; + /// + /// Gets the AutoHideWindow property. This dependency property + /// indicates the currently shown autohide window. + /// + public LayoutAutoHideWindowControl AutoHideWindow + { + get + { + return ( LayoutAutoHideWindowControl )GetValue( AutoHideWindowProperty ); + } + } + /// + /// Provides a secure method for setting the AutoHideWindow property. + /// This dependency property indicates the currently shown autohide window. + /// + /// The new value for the property. + protected void SetAutoHideWindow( LayoutAutoHideWindowControl value ) + { + SetValue( AutoHideWindowPropertyKey, value ); + } - if (fwWidth == 0.0) - fwWidth = paneAsWithActualSize.ActualWidth; - if (fwHeight == 0.0) - fwHeight = paneAsWithActualSize.ActualHeight; + /// + /// Handles changes to the AutoHideWindow property. + /// + private static void OnAutoHideWindowChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnAutoHideWindowChanged( e ); + } - var destPane = new LayoutAnchorablePane() - { - DockWidth = paneAsPositionableElement.DockWidth, - DockHeight = paneAsPositionableElement.DockHeight, - DockMinHeight = paneAsPositionableElement.DockMinHeight, - DockMinWidth = paneAsPositionableElement.DockMinWidth, - FloatingLeft = paneAsPositionableElement.FloatingLeft, - FloatingTop = paneAsPositionableElement.FloatingTop, - FloatingWidth = paneAsPositionableElement.FloatingWidth, - FloatingHeight = paneAsPositionableElement.FloatingHeight, - }; + /// + /// Provides derived classes an opportunity to handle changes to the AutoHideWindow property. + /// + protected virtual void OnAutoHideWindowChanged( DependencyPropertyChangedEventArgs e ) + { + if( e.OldValue != null ) + InternalRemoveLogicalChild( e.OldValue ); + if( e.NewValue != null ) + InternalAddLogicalChild( e.NewValue ); - bool savePreviousContainer = paneModel.FindParent() == null; - int currentSelectedContentIndex = paneModel.SelectedContentIndex; - while (paneModel.Children.Count > 0) - { - var contentModel = paneModel.Children[paneModel.Children.Count - 1] as LayoutAnchorable; + } - if (savePreviousContainer) - { - var contentModelAsPreviousContainer = contentModel as ILayoutPreviousContainer; - contentModelAsPreviousContainer.PreviousContainer = paneModel; - contentModel.PreviousContainerIndex = paneModel.Children.Count - 1; - } + #endregion + + + + #endregion + // #region AutoHide window + //WeakReference _currentAutohiddenAnchor = null; + //internal void ShowAutoHideWindow(LayoutAnchorControl anchor) + //{ + // if (_autohideArea == null) + // return; + + // if (AutoHideWindow != null && AutoHideWindow.Model == anchor.Model) + // return; + + // Trace.WriteLine("ShowAutoHideWindow()"); + + // _currentAutohiddenAnchor = new WeakReference(anchor); + + // HideAutoHideWindow(anchor); + + // SetAutoHideWindow(new LayoutAutoHideWindowControl(anchor)); + //} + + //internal void HideAutoHideWindow(LayoutAnchorControl anchor) + //{ + // if (AutoHideWindow != null) + // { + // if (anchor == _currentAutohiddenAnchor.GetValueOrDefault()) + // { + // Trace.WriteLine("AutoHideWindow()"); + // AutoHideWindow.Dispose(); + // SetAutoHideWindow(null); + // } + // } + //} + + //FrameworkElement _autohideArea; + //internal FrameworkElement GetAutoHideAreaElement() + //{ + // return _autohideArea; + //} + + //void SetupAutoHideArea() + //{ + // _autohideArea = GetTemplateChild("PART_AutoHideArea") as FrameworkElement; + //} + + // #region AutoHideWindow + + ///// + ///// AutoHideWindow Read-Only Dependency Property + ///// + //private static readonly DependencyPropertyKey AutoHideWindowPropertyKey + // = DependencyProperty.RegisterReadOnly("AutoHideWindow", typeof(LayoutAutoHideWindowControl), typeof(DockingManager), + // new FrameworkPropertyMetadata((LayoutAutoHideWindowControl)null, + // new PropertyChangedCallback(OnAutoHideWindowChanged))); + + //public static readonly DependencyProperty AutoHideWindowProperty + // = AutoHideWindowPropertyKey.DependencyProperty; + + ///// + ///// Gets the AutoHideWindow property. This dependency property + ///// indicates the currently shown autohide window. + ///// + //public LayoutAutoHideWindowControl AutoHideWindow + //{ + // get { return (LayoutAutoHideWindowControl)GetValue(AutoHideWindowProperty); } + //} + + ///// + ///// Provides a secure method for setting the AutoHideWindow property. + ///// This dependency property indicates the currently shown autohide window. + ///// + ///// The new value for the property. + //protected void SetAutoHideWindow(LayoutAutoHideWindowControl value) + //{ + // SetValue(AutoHideWindowPropertyKey, value); + //} + + ///// + ///// Handles changes to the AutoHideWindow property. + ///// + //private static void OnAutoHideWindowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + //{ + // ((DockingManager)d).OnAutoHideWindowChanged(e); + //} + + ///// + ///// Provides derived classes an opportunity to handle changes to the AutoHideWindow property. + ///// + //protected virtual void OnAutoHideWindowChanged(DependencyPropertyChangedEventArgs e) + //{ + // if (e.OldValue != null) + // ((ILogicalChildrenContainer)this).InternalRemoveLogicalChild(e.OldValue); + // if (e.NewValue != null) + // ((ILogicalChildrenContainer)this).InternalAddLogicalChild(e.NewValue); + //} + + // #endregion + + + + // #endregion + + #region Floating Windows + List _fwList = new List(); + + internal void StartDraggingFloatingWindowForContent( LayoutContent contentModel, bool startDrag = true ) + { + if( !contentModel.CanFloat ) + return; + var contentModelAsAnchorable = contentModel as LayoutAnchorable; + if( contentModelAsAnchorable != null && + contentModelAsAnchorable.IsAutoHidden ) + contentModelAsAnchorable.ToggleAutoHide(); + + var parentPane = contentModel.Parent as ILayoutPane; + var parentPaneAsPositionableElement = contentModel.Parent as ILayoutPositionableElement; + var parentPaneAsWithActualSize = contentModel.Parent as ILayoutPositionableElementWithActualSize; + var contentModelParentChildrenIndex = parentPane.Children.ToList().IndexOf( contentModel ); + + if( contentModel.FindParent() == null ) + { + ( ( ILayoutPreviousContainer )contentModel ).PreviousContainer = parentPane; + contentModel.PreviousContainerIndex = contentModelParentChildrenIndex; + } - paneModel.RemoveChildAt(paneModel.Children.Count - 1); - destPane.Children.Insert(0, contentModel); - } + parentPane.RemoveChildAt( contentModelParentChildrenIndex ); - if (destPane.Children.Count > 0) - { - destPane.SelectedContentIndex = currentSelectedContentIndex; - } + double fwWidth = contentModel.FloatingWidth; + double fwHeight = contentModel.FloatingHeight; + if( fwWidth == 0.0 ) + fwWidth = parentPaneAsPositionableElement.FloatingWidth; + if( fwHeight == 0.0 ) + fwHeight = parentPaneAsPositionableElement.FloatingHeight; - LayoutFloatingWindow fw; - LayoutFloatingWindowControl fwc; - fw = new LayoutAnchorableFloatingWindow() - { - RootPanel = new LayoutAnchorablePaneGroup( - destPane) - { - DockHeight = destPane.DockHeight, - DockWidth = destPane.DockWidth, - DockMinHeight = destPane.DockMinHeight, - DockMinWidth = destPane.DockMinWidth, - } - }; + if( fwWidth == 0.0 ) + fwWidth = parentPaneAsWithActualSize.ActualWidth + 10; //10 includes BorderThickness and Margins inside LayoutDocumentFloatingWindowControl. + if( fwHeight == 0.0 ) + fwHeight = parentPaneAsWithActualSize.ActualHeight + 10; //10 includes BorderThickness and Margins inside LayoutDocumentFloatingWindowControl. - Layout.FloatingWindows.Add(fw); + LayoutFloatingWindow fw; + LayoutFloatingWindowControl fwc; + if( contentModel is LayoutAnchorable ) + { + var anchorableContent = contentModel as LayoutAnchorable; + fw = new LayoutAnchorableFloatingWindow() + { + RootPanel = new LayoutAnchorablePaneGroup( + new LayoutAnchorablePane( anchorableContent ) + { + DockWidth = parentPaneAsPositionableElement.DockWidth, + DockHeight = parentPaneAsPositionableElement.DockHeight, + DockMinHeight = parentPaneAsPositionableElement.DockMinHeight, + DockMinWidth = parentPaneAsPositionableElement.DockMinWidth, + FloatingLeft = parentPaneAsPositionableElement.FloatingLeft, + FloatingTop = parentPaneAsPositionableElement.FloatingTop, + FloatingWidth = parentPaneAsPositionableElement.FloatingWidth, + FloatingHeight = parentPaneAsPositionableElement.FloatingHeight, + } ) + }; + + Layout.FloatingWindows.Add( fw ); + + fwc = new LayoutAnchorableFloatingWindowControl( + fw as LayoutAnchorableFloatingWindow ) + { + Width = fwWidth, + Height = fwHeight, + Left = contentModel.FloatingLeft, + Top = contentModel.FloatingTop + }; + } + else + { + var anchorableDocument = contentModel as LayoutDocument; + fw = new LayoutDocumentFloatingWindow() + { + RootDocument = anchorableDocument + }; - fwc = new LayoutAnchorableFloatingWindowControl( - fw as LayoutAnchorableFloatingWindow) - { - Width = fwWidth, - Height = fwHeight - }; + Layout.FloatingWindows.Add( fw ); + fwc = new LayoutDocumentFloatingWindowControl( + fw as LayoutDocumentFloatingWindow ) + { + Width = fwWidth, + Height = fwHeight, + Left = contentModel.FloatingLeft, + Top = contentModel.FloatingTop + }; + } - //fwc.Owner = Window.GetWindow(this); - //fwc.SetParentToMainWindowOf(this); + //fwc.Owner = Window.GetWindow(this); + //fwc.SetParentToMainWindowOf(this); - _fwList.Add(fwc); + _fwList.Add( fwc ); - Layout.CollectGarbage(); + Layout.CollectGarbage(); - InvalidateArrange(); + UpdateLayout(); + Dispatcher.BeginInvoke( new Action( () => + { + if( startDrag ) fwc.AttachDrag(); - fwc.Show(); + fwc.Show(); + } ), DispatcherPriority.Send ); + } - } + internal void StartDraggingFloatingWindowForPane( LayoutAnchorablePane paneModel ) + { + if( paneModel.Children.Any( c => !c.CanFloat ) ) + return; + var paneAsPositionableElement = paneModel as ILayoutPositionableElement; + var paneAsWithActualSize = paneModel as ILayoutPositionableElementWithActualSize; + + double fwWidth = paneAsPositionableElement.FloatingWidth; + double fwHeight = paneAsPositionableElement.FloatingHeight; + double fwLeft = paneAsPositionableElement.FloatingLeft; + double fwTop = paneAsPositionableElement.FloatingTop; + + if( fwWidth == 0.0 ) + fwWidth = paneAsWithActualSize.ActualWidth + 10; //10 includes BorderThickness and Margins inside LayoutAnchorableFloatingWindowControl. + if( fwHeight == 0.0 ) + fwHeight = paneAsWithActualSize.ActualHeight + 10; //10 includes BorderThickness and Margins inside LayoutAnchorableFloatingWindowControl. + + var destPane = new LayoutAnchorablePane() + { + DockWidth = paneAsPositionableElement.DockWidth, + DockHeight = paneAsPositionableElement.DockHeight, + DockMinHeight = paneAsPositionableElement.DockMinHeight, + DockMinWidth = paneAsPositionableElement.DockMinWidth, + FloatingLeft = paneAsPositionableElement.FloatingLeft, + FloatingTop = paneAsPositionableElement.FloatingTop, + FloatingWidth = paneAsPositionableElement.FloatingWidth, + FloatingHeight = paneAsPositionableElement.FloatingHeight, + }; + + bool savePreviousContainer = paneModel.FindParent() == null; + int currentSelectedContentIndex = paneModel.SelectedContentIndex; + while( paneModel.Children.Count > 0 ) + { + var contentModel = paneModel.Children[ paneModel.Children.Count - 1 ] as LayoutAnchorable; - internal IEnumerable GetFloatingWindowsByZOrder() + if( savePreviousContainer ) { - var parentWindow = Window.GetWindow(this); - - if (parentWindow == null) - yield break; + var contentModelAsPreviousContainer = contentModel as ILayoutPreviousContainer; + contentModelAsPreviousContainer.PreviousContainer = paneModel; + contentModel.PreviousContainerIndex = paneModel.Children.Count - 1; + } - IntPtr windowParentHanlde = new WindowInteropHelper(parentWindow).Handle; + paneModel.RemoveChildAt( paneModel.Children.Count - 1 ); + destPane.Children.Insert( 0, contentModel ); + } - IntPtr currentHandle = Win32Helper.GetWindow(windowParentHanlde, (uint)Win32Helper.GetWindow_Cmd.GW_HWNDFIRST); - while (currentHandle != IntPtr.Zero) - { - LayoutFloatingWindowControl ctrl = _fwList.FirstOrDefault(fw => new WindowInteropHelper(fw).Handle == currentHandle); - if (ctrl != null && ctrl.Model.Root.Manager == this) - yield return ctrl; + if( destPane.Children.Count > 0 ) + { + destPane.SelectedContentIndex = currentSelectedContentIndex; + } - currentHandle = Win32Helper.GetWindow(currentHandle, (uint)Win32Helper.GetWindow_Cmd.GW_HWNDNEXT); - } - } - internal void RemoveFloatingWindow(LayoutFloatingWindowControl floatingWindow) + LayoutFloatingWindow fw; + LayoutFloatingWindowControl fwc; + fw = new LayoutAnchorableFloatingWindow() + { + RootPanel = new LayoutAnchorablePaneGroup( + destPane ) { - _fwList.Remove(floatingWindow); + DockHeight = destPane.DockHeight, + DockWidth = destPane.DockWidth, + DockMinHeight = destPane.DockMinHeight, + DockMinWidth = destPane.DockMinWidth, } + }; - public IEnumerable FloatingWindows - { - get { return _fwList; } - } - #endregion + Layout.FloatingWindows.Add( fw ); - #region OverlayWindow + fwc = new LayoutAnchorableFloatingWindowControl( + fw as LayoutAnchorableFloatingWindow ) + { + Width = fwWidth, + Height = fwHeight + }; - bool IOverlayWindowHost.HitTest(Point dragPoint) - { - Rect detectionRect = new Rect(this.PointToScreenDPIWithoutFlowDirection(new Point()), this.TransformActualSizeToAncestor()); - return detectionRect.Contains(dragPoint); - } - DockingManager IOverlayWindowHost.Manager - { - get { return this; } - } - OverlayWindow _overlayWindow = null; - void CreateOverlayWindow() - { - if (_overlayWindow == null) - { - _overlayWindow = new OverlayWindow(this); - } - Rect rectWindow = new Rect(this.PointToScreenDPIWithoutFlowDirection(new Point()), this.TransformActualSizeToAncestor()); - _overlayWindow.Left = rectWindow.Left; - _overlayWindow.Top = rectWindow.Top; - _overlayWindow.Width = rectWindow.Width; - _overlayWindow.Height = rectWindow.Height; - } + //fwc.Owner = Window.GetWindow(this); + //fwc.SetParentToMainWindowOf(this); - void DestroyOverlayWindow() - { - if (_overlayWindow != null) - { - _overlayWindow.Close(); - _overlayWindow = null; - } - } - IOverlayWindow IOverlayWindowHost.ShowOverlayWindow(LayoutFloatingWindowControl draggingWindow) - { - CreateOverlayWindow(); - _overlayWindow.Owner = draggingWindow; - _overlayWindow.EnableDropTargets(); - _overlayWindow.Show(); - return _overlayWindow; - } + _fwList.Add( fwc ); - void IOverlayWindowHost.HideOverlayWindow() - { - _areas = null; - _overlayWindow.Owner = null; - _overlayWindow.HideDropTargets(); - } + Layout.CollectGarbage(); - List _areas = null; + InvalidateArrange(); - IEnumerable IOverlayWindowHost.GetDropAreas(LayoutFloatingWindowControl draggingWindow) - { - if (_areas != null) - return _areas; + fwc.AttachDrag(); + fwc.Show(); - bool isDraggingDocuments = draggingWindow.Model is LayoutDocumentFloatingWindow; + } - _areas = new List(); + internal IEnumerable GetFloatingWindowsByZOrder() + { + var parentWindow = Window.GetWindow( this ); - if (!isDraggingDocuments) - { - _areas.Add(new DropArea( - this, - DropAreaType.DockingManager)); + if( parentWindow == null ) + yield break; - foreach (var areaHost in this.FindVisualChildren()) - { - if (areaHost.Model.Descendents().Any()) - { - _areas.Add(new DropArea( - areaHost, - DropAreaType.AnchorablePane)); - } - } - } + IntPtr windowParentHanlde = new WindowInteropHelper( parentWindow ).Handle; - foreach (var areaHost in this.FindVisualChildren()) - { - _areas.Add(new DropArea( - areaHost, - DropAreaType.DocumentPane)); - } + IntPtr currentHandle = Win32Helper.GetWindow( windowParentHanlde, ( uint )Win32Helper.GetWindow_Cmd.GW_HWNDFIRST ); + while( currentHandle != IntPtr.Zero ) + { + LayoutFloatingWindowControl ctrl = _fwList.FirstOrDefault( fw => new WindowInteropHelper( fw ).Handle == currentHandle ); + if( ctrl != null && ctrl.Model.Root.Manager == this ) + yield return ctrl; - foreach (var areaHost in this.FindVisualChildren()) - { - var documentGroupModel = areaHost.Model as LayoutDocumentPaneGroup; - if (documentGroupModel.Children.Where(c => c.IsVisible).Count() == 0) - { - _areas.Add(new DropArea( - areaHost, - DropAreaType.DocumentPaneGroup)); - } - } + currentHandle = Win32Helper.GetWindow( currentHandle, ( uint )Win32Helper.GetWindow_Cmd.GW_HWNDNEXT ); + } + } - return _areas; - } + internal void RemoveFloatingWindow( LayoutFloatingWindowControl floatingWindow ) + { + _fwList.Remove( floatingWindow ); + } - protected override Size ArrangeOverride(Size arrangeBounds) - { - _areas = null; - return base.ArrangeOverride(arrangeBounds); - } + public IEnumerable FloatingWindows + { + get + { + return _fwList; + } + } + #endregion + + #region OverlayWindow + + bool IOverlayWindowHost.HitTest( Point dragPoint ) + { + Rect detectionRect = new Rect( this.PointToScreenDPIWithoutFlowDirection( new Point() ), this.TransformActualSizeToAncestor() ); + return detectionRect.Contains( dragPoint ); + } - #endregion + DockingManager IOverlayWindowHost.Manager + { + get + { + return this; + } + } - #region LayoutDocument & LayoutAnchorable Templates + OverlayWindow _overlayWindow = null; + void CreateOverlayWindow() + { + if( _overlayWindow == null ) + { + _overlayWindow = new OverlayWindow( this ); + } + Rect rectWindow = new Rect( this.PointToScreenDPIWithoutFlowDirection( new Point() ), this.TransformActualSizeToAncestor() ); + _overlayWindow.Left = rectWindow.Left; + _overlayWindow.Top = rectWindow.Top; + _overlayWindow.Width = rectWindow.Width; + _overlayWindow.Height = rectWindow.Height; + } - #region LayoutItemTemplate + void DestroyOverlayWindow() + { + if( _overlayWindow != null ) + { + _overlayWindow.Close(); + _overlayWindow = null; + } + } - /// - /// LayoutItemTemplate Dependency Property - /// - public static readonly DependencyProperty LayoutItemTemplateProperty = - DependencyProperty.Register("LayoutItemTemplate", typeof(DataTemplate), typeof(DockingManager), - new FrameworkPropertyMetadata((DataTemplate)null, - new PropertyChangedCallback(OnLayoutItemTemplateChanged))); + IOverlayWindow IOverlayWindowHost.ShowOverlayWindow( LayoutFloatingWindowControl draggingWindow ) + { + CreateOverlayWindow(); + _overlayWindow.Owner = draggingWindow; + _overlayWindow.EnableDropTargets(); + _overlayWindow.Show(); + return _overlayWindow; + } - /// - /// Gets or sets the AnchorableTemplate property. This dependency property - /// indicates the template to use to render anchorable and document contents. - /// - public DataTemplate LayoutItemTemplate - { - get { return (DataTemplate)GetValue(LayoutItemTemplateProperty); } - set { SetValue(LayoutItemTemplateProperty, value); } - } + void IOverlayWindowHost.HideOverlayWindow() + { + _areas = null; + _overlayWindow.Owner = null; + _overlayWindow.HideDropTargets(); + } - /// - /// Handles changes to the AnchorableTemplate property. - /// - private static void OnLayoutItemTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnLayoutItemTemplateChanged(e); - } + List _areas = null; - /// - /// Provides derived classes an opportunity to handle changes to the AnchorableTemplate property. - /// - protected virtual void OnLayoutItemTemplateChanged(DependencyPropertyChangedEventArgs e) - { - } + IEnumerable IOverlayWindowHost.GetDropAreas( LayoutFloatingWindowControl draggingWindow ) + { + if( _areas != null ) + return _areas; - #endregion + bool isDraggingDocuments = draggingWindow.Model is LayoutDocumentFloatingWindow; - #region LayoutItemTemplateSelector + _areas = new List(); - /// - /// LayoutItemTemplateSelector Dependency Property - /// - public static readonly DependencyProperty LayoutItemTemplateSelectorProperty = - DependencyProperty.Register("LayoutItemTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), - new FrameworkPropertyMetadata((DataTemplateSelector)null, - new PropertyChangedCallback(OnLayoutItemTemplateSelectorChanged))); + if( !isDraggingDocuments ) + { + _areas.Add( new DropArea( + this, + DropAreaType.DockingManager ) ); - /// - /// Gets or sets the LayoutItemTemplateSelector property. This dependency property - /// indicates selector object to use for anchorable templates. - /// - public DataTemplateSelector LayoutItemTemplateSelector + foreach( var areaHost in this.FindVisualChildren() ) { - get { return (DataTemplateSelector)GetValue(LayoutItemTemplateSelectorProperty); } - set { SetValue(LayoutItemTemplateSelectorProperty, value); } + if( areaHost.Model.Descendents().Any() ) + { + _areas.Add( new DropArea( + areaHost, + DropAreaType.AnchorablePane ) ); + } } + } - /// - /// Handles changes to the LayoutItemTemplateSelector property. - /// - private static void OnLayoutItemTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnLayoutItemTemplateSelectorChanged(e); - } + foreach( var areaHost in this.FindVisualChildren() ) + { + _areas.Add( new DropArea( + areaHost, + DropAreaType.DocumentPane ) ); + } - /// - /// Provides derived classes an opportunity to handle changes to the LayoutItemTemplateSelector property. - /// - protected virtual void OnLayoutItemTemplateSelectorChanged(DependencyPropertyChangedEventArgs e) + foreach( var areaHost in this.FindVisualChildren() ) + { + var documentGroupModel = areaHost.Model as LayoutDocumentPaneGroup; + if( documentGroupModel.Children.Where( c => c.IsVisible ).Count() == 0 ) { + _areas.Add( new DropArea( + areaHost, + DropAreaType.DocumentPaneGroup ) ); } + } - #endregion + return _areas; + } + protected override Size ArrangeOverride( Size arrangeBounds ) + { + _areas = null; + return base.ArrangeOverride( arrangeBounds ); + } - #endregion + #endregion - #region DocumentsSource + #region LayoutDocument & LayoutAnchorable Templates - /// - /// DocumentsSource Dependency Property - /// - public static readonly DependencyProperty DocumentsSourceProperty = - DependencyProperty.Register("DocumentsSource", typeof(IEnumerable), typeof(DockingManager), - new FrameworkPropertyMetadata((IEnumerable)null, - new PropertyChangedCallback(OnDocumentsSourceChanged))); + #region LayoutItemTemplate - /// - /// Gets or sets the DocumentsSource property. This dependency property - /// indicates the source collection of documents. - /// - public IEnumerable DocumentsSource - { - get { return (IEnumerable)GetValue(DocumentsSourceProperty); } - set { SetValue(DocumentsSourceProperty, value); } - } + /// + /// LayoutItemTemplate Dependency Property + /// + public static readonly DependencyProperty LayoutItemTemplateProperty = + DependencyProperty.Register( "LayoutItemTemplate", typeof( DataTemplate ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( DataTemplate )null, + new PropertyChangedCallback( OnLayoutItemTemplateChanged ) ) ); - /// - /// Handles changes to the DocumentsSource property. - /// - private static void OnDocumentsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnDocumentsSourceChanged(e); - } + /// + /// Gets or sets the AnchorableTemplate property. This dependency property + /// indicates the template to use to render anchorable and document contents. + /// + public DataTemplate LayoutItemTemplate + { + get + { + return ( DataTemplate )GetValue( LayoutItemTemplateProperty ); + } + set + { + SetValue( LayoutItemTemplateProperty, value ); + } + } - /// - /// Provides derived classes an opportunity to handle changes to the DocumentsSource property. - /// - protected virtual void OnDocumentsSourceChanged(DependencyPropertyChangedEventArgs e) - { - DetachDocumentsSource(Layout, e.OldValue as IEnumerable); - AttachDocumentsSource(Layout, e.NewValue as IEnumerable); - } + /// + /// Handles changes to the AnchorableTemplate property. + /// + private static void OnLayoutItemTemplateChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnLayoutItemTemplateChanged( e ); + } + /// + /// Provides derived classes an opportunity to handle changes to the AnchorableTemplate property. + /// + protected virtual void OnLayoutItemTemplateChanged( DependencyPropertyChangedEventArgs e ) + { + } - void AttachDocumentsSource(LayoutRoot layout, IEnumerable documentsSource) - { - if (documentsSource == null) - return; + #endregion - if (layout == null) - return; + #region LayoutItemTemplateSelector - //if (layout.Descendents().OfType().Any()) - // throw new InvalidOperationException("Unable to set the DocumentsSource property if LayoutDocument objects are already present in the model"); - var documentsImported = layout.Descendents().OfType().Select(d => d.Content).ToArray(); - var documents = documentsSource as IEnumerable; - var listOfDocumentsToImport = new List(documents.OfType()); + /// + /// LayoutItemTemplateSelector Dependency Property + /// + public static readonly DependencyProperty LayoutItemTemplateSelectorProperty = + DependencyProperty.Register( "LayoutItemTemplateSelector", typeof( DataTemplateSelector ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( DataTemplateSelector )null, + new PropertyChangedCallback( OnLayoutItemTemplateSelectorChanged ) ) ); - foreach (var document in listOfDocumentsToImport.ToArray()) - { - if (documentsImported.Contains(document)) - listOfDocumentsToImport.Remove(document); - } + /// + /// Gets or sets the LayoutItemTemplateSelector property. This dependency property + /// indicates selector object to use for anchorable templates. + /// + public DataTemplateSelector LayoutItemTemplateSelector + { + get + { + return ( DataTemplateSelector )GetValue( LayoutItemTemplateSelectorProperty ); + } + set + { + SetValue( LayoutItemTemplateSelectorProperty, value ); + } + } + /// + /// Handles changes to the LayoutItemTemplateSelector property. + /// + private static void OnLayoutItemTemplateSelectorChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnLayoutItemTemplateSelectorChanged( e ); + } - LayoutDocumentPane documentPane = null; - if (layout.LastFocusedDocument != null) - { - documentPane = layout.LastFocusedDocument.Parent as LayoutDocumentPane; - } + /// + /// Provides derived classes an opportunity to handle changes to the LayoutItemTemplateSelector property. + /// + protected virtual void OnLayoutItemTemplateSelectorChanged( DependencyPropertyChangedEventArgs e ) + { + } - if (documentPane == null) - { - documentPane = layout.Descendents().OfType().FirstOrDefault(); - } + #endregion - //if (documentPane == null) - // throw new InvalidOperationException("Layout must contains at least one LayoutDocumentPane in order to host documents"); - _suspendLayoutItemCreation = true; - foreach (var documentContentToImport in listOfDocumentsToImport) - { + #endregion - //documentPane.Children.Add(new LayoutDocument() { Content = documentToImport }); + #region DocumentsSource - var documentToImport = new LayoutDocument() - { - Content = documentContentToImport - }; + /// + /// DocumentsSource Dependency Property + /// + public static readonly DependencyProperty DocumentsSourceProperty = + DependencyProperty.Register( "DocumentsSource", typeof( IEnumerable ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( IEnumerable )null, + new PropertyChangedCallback( OnDocumentsSourceChanged ) ) ); - bool added = false; - if (LayoutUpdateStrategy != null) - { - added = LayoutUpdateStrategy.BeforeInsertDocument(layout, documentToImport, documentPane); - } + /// + /// Gets or sets the DocumentsSource property. This dependency property + /// indicates the source collection of documents. + /// + public IEnumerable DocumentsSource + { + get + { + return ( IEnumerable )GetValue( DocumentsSourceProperty ); + } + set + { + SetValue( DocumentsSourceProperty, value ); + } + } - if (!added) - { - if (documentPane == null) - throw new InvalidOperationException("Layout must contains at least one LayoutDocumentPane in order to host documents"); + /// + /// Handles changes to the DocumentsSource property. + /// + private static void OnDocumentsSourceChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnDocumentsSourceChanged( e ); + } - documentPane.Children.Add(documentToImport); - added = true; - } + /// + /// Provides derived classes an opportunity to handle changes to the DocumentsSource property. + /// + protected virtual void OnDocumentsSourceChanged( DependencyPropertyChangedEventArgs e ) + { + DetachDocumentsSource( Layout, e.OldValue as IEnumerable ); + AttachDocumentsSource( Layout, e.NewValue as IEnumerable ); + } - if (LayoutUpdateStrategy != null) - LayoutUpdateStrategy.AfterInsertDocument(layout, documentToImport); + void AttachDocumentsSource( LayoutRoot layout, IEnumerable documentsSource ) + { + if( documentsSource == null ) + return; - CreateDocumentLayoutItem(documentToImport); + if( layout == null ) + return; - } - _suspendLayoutItemCreation = false; + //if (layout.Descendents().OfType().Any()) + // throw new InvalidOperationException("Unable to set the DocumentsSource property if LayoutDocument objects are already present in the model"); + var documentsImported = layout.Descendents().OfType().Select( d => d.Content ).ToArray(); + var documents = documentsSource as IEnumerable; + var listOfDocumentsToImport = new List( documents.OfType() ); + foreach( var document in listOfDocumentsToImport.ToArray() ) + { + if( documentsImported.Contains( document ) ) + listOfDocumentsToImport.Remove( document ); + } - var documentsSourceAsNotifier = documentsSource as INotifyCollectionChanged; - if (documentsSourceAsNotifier != null) - documentsSourceAsNotifier.CollectionChanged += new NotifyCollectionChangedEventHandler(documentsSourceElementsChanged); - } - internal bool SuspendDocumentsSourceBinding = false; + LayoutDocumentPane documentPane = null; + if( layout.LastFocusedDocument != null ) + { + documentPane = layout.LastFocusedDocument.Parent as LayoutDocumentPane; + } - void documentsSourceElementsChanged(object sender, NotifyCollectionChangedEventArgs e) - { - if (Layout == null) - return; + if( documentPane == null ) + { + documentPane = layout.Descendents().OfType().FirstOrDefault(); + } - //When deserializing documents are created automatically by the deserializer - if (SuspendDocumentsSourceBinding) - return; + //if (documentPane == null) + // throw new InvalidOperationException("Layout must contains at least one LayoutDocumentPane in order to host documents"); - //handle remove - if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || - e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace) - { - if (e.OldItems != null) - { - var documentsToRemove = Layout.Descendents().OfType().Where(d => e.OldItems.Contains(d.Content)).ToArray(); - foreach (var documentToRemove in documentsToRemove) - { - (documentToRemove.Parent as ILayoutContainer).RemoveChild( - documentToRemove); - this.RemoveViewFromLogicalChild( documentToRemove ); - } - } - } + _suspendLayoutItemCreation = true; + foreach( var documentContentToImport in listOfDocumentsToImport ) + { - //handle add - if (e.NewItems != null && - (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || - e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace)) - { - if (e.NewItems != null) - { - LayoutDocumentPane documentPane = null; - if (Layout.LastFocusedDocument != null) - { - documentPane = Layout.LastFocusedDocument.Parent as LayoutDocumentPane; - } + //documentPane.Children.Add(new LayoutDocument() { Content = documentToImport }); - if (documentPane == null) - { - documentPane = Layout.Descendents().OfType().FirstOrDefault(); - } + var documentToImport = new LayoutDocument() + { + Content = documentContentToImport + }; - //if (documentPane == null) - // throw new InvalidOperationException("Layout must contains at least one LayoutDocumentPane in order to host documents"); + bool added = false; + if( LayoutUpdateStrategy != null ) + { + added = LayoutUpdateStrategy.BeforeInsertDocument( layout, documentToImport, documentPane ); + } - _suspendLayoutItemCreation = true; + if( !added ) + { + if( documentPane == null ) + throw new InvalidOperationException( "Layout must contains at least one LayoutDocumentPane in order to host documents" ); - foreach (var documentContentToImport in e.NewItems) - { - var documentToImport = new LayoutDocument() - { - Content = documentContentToImport - }; + documentPane.Children.Add( documentToImport ); + added = true; + } - bool added = false; - if (LayoutUpdateStrategy != null) - { - added = LayoutUpdateStrategy.BeforeInsertDocument(Layout, documentToImport, documentPane); - } + if( LayoutUpdateStrategy != null ) + LayoutUpdateStrategy.AfterInsertDocument( layout, documentToImport ); - if (!added) - { - if (documentPane == null) - throw new InvalidOperationException("Layout must contains at least one LayoutDocumentPane in order to host documents"); - documentPane.Children.Add(documentToImport); - added = true; - } + CreateDocumentLayoutItem( documentToImport ); - if (LayoutUpdateStrategy != null) - { - LayoutUpdateStrategy.AfterInsertDocument(Layout, documentToImport); - } + } + _suspendLayoutItemCreation = false; - var root = documentToImport.Root; + var documentsSourceAsNotifier = documentsSource as INotifyCollectionChanged; + if( documentsSourceAsNotifier != null ) + documentsSourceAsNotifier.CollectionChanged += new NotifyCollectionChangedEventHandler( documentsSourceElementsChanged ); + } - if (root != null && root.Manager == this) - { - CreateDocumentLayoutItem(documentToImport); - } - } - _suspendLayoutItemCreation = false; - } - } + internal bool SuspendDocumentsSourceBinding = false; - if (e.Action == NotifyCollectionChangedAction.Reset) - { - //NOTE: I'm going to clear every document present in layout but - //some documents may have been added directly to the layout, for now I clear them too - var documentsToRemove = Layout.Descendents().OfType().ToArray(); - foreach (var documentToRemove in documentsToRemove) - { - (documentToRemove.Parent as ILayoutContainer).RemoveChild( - documentToRemove); - this.RemoveViewFromLogicalChild( documentToRemove ); - } - } + void documentsSourceElementsChanged( object sender, NotifyCollectionChangedEventArgs e ) + { + if( Layout == null ) + return; - if (Layout != null) - { - Layout.CollectGarbage(); - } - } + //When deserializing documents are created automatically by the deserializer + if( SuspendDocumentsSourceBinding ) + return; - void DetachDocumentsSource(LayoutRoot layout, IEnumerable documentsSource) + //handle remove + if( e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace ) + { + if( e.OldItems != null ) { - if (documentsSource == null) - return; - - if (layout == null) - return; - - var documentsToRemove = layout.Descendents().OfType() - .Where(d => documentsSource.Contains(d.Content)).ToArray(); + var documentsToRemove = Layout.Descendents().OfType().Where( d => e.OldItems.Contains( d.Content ) ).ToArray(); + foreach( var documentToRemove in documentsToRemove ) + { + ( documentToRemove.Parent as ILayoutContainer ).RemoveChild( + documentToRemove ); + this.RemoveViewFromLogicalChild( documentToRemove ); + } + } + } - foreach (var documentToRemove in documentsToRemove) - { - (documentToRemove.Parent as ILayoutContainer).RemoveChild( - documentToRemove); - this.RemoveViewFromLogicalChild( documentToRemove ); - } + //handle add + if( e.NewItems != null && + ( e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace ) ) + { + if( e.NewItems != null ) + { + LayoutDocumentPane documentPane = null; + if( Layout.LastFocusedDocument != null ) + { + documentPane = Layout.LastFocusedDocument.Parent as LayoutDocumentPane; + } - var documentsSourceAsNotifier = documentsSource as INotifyCollectionChanged; - if (documentsSourceAsNotifier != null) - documentsSourceAsNotifier.CollectionChanged -= new NotifyCollectionChangedEventHandler(documentsSourceElementsChanged); - } + if( documentPane == null ) + { + documentPane = Layout.Descendents().OfType().FirstOrDefault(); + } + //if (documentPane == null) + // throw new InvalidOperationException("Layout must contains at least one LayoutDocumentPane in order to host documents"); - #endregion + _suspendLayoutItemCreation = true; - #region DocumentCloseCommand + foreach( var documentContentToImport in e.NewItems ) + { + var documentToImport = new LayoutDocument() + { + Content = documentContentToImport + }; - internal void _ExecuteCloseCommand(LayoutDocument document) - { - if (DocumentClosing != null) + bool added = false; + if( LayoutUpdateStrategy != null ) { - var evargs = new DocumentClosingEventArgs(document); - DocumentClosing(this, evargs); - if (evargs.Cancel) - return; + added = LayoutUpdateStrategy.BeforeInsertDocument( Layout, documentToImport, documentPane ); } - if( document.CloseDocument() ) + if( !added ) { - this.RemoveViewFromLogicalChild( document ); + if( documentPane == null ) + throw new InvalidOperationException( "Layout must contains at least one LayoutDocumentPane in order to host documents" ); - if( DocumentClosed != null ) - { - var evargs = new DocumentClosedEventArgs( document ); - DocumentClosed( this, evargs ); - } + documentPane.Children.Add( documentToImport ); + added = true; } - } - - /// - /// Event fired when a document is about to be closed - /// - /// Subscribers have the opportuniy to cancel the operation. - public event EventHandler DocumentClosing; - - /// - /// Event fired after a document is closed - /// - public event EventHandler DocumentClosed; + if( LayoutUpdateStrategy != null ) + { + LayoutUpdateStrategy.AfterInsertDocument( Layout, documentToImport ); + } - #endregion + var root = documentToImport.Root; - internal void _ExecuteCloseAllButThisCommand(LayoutContent contentSelected) - { - foreach (var contentToClose in Layout.Descendents().OfType().Where(d => d != contentSelected && (d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow)).ToArray()) + if( root != null && root.Manager == this ) { - this.Close( contentToClose ); + CreateDocumentLayoutItem( documentToImport ); } + } + _suspendLayoutItemCreation = false; } + } - internal void _ExecuteCloseAllCommand( LayoutContent contentSelected ) + if( e.Action == NotifyCollectionChangedAction.Reset ) + { + //NOTE: I'm going to clear every document present in layout but + //some documents may have been added directly to the layout, for now I clear them too + var documentsToRemove = Layout.Descendents().OfType().ToArray(); + foreach( var documentToRemove in documentsToRemove ) { - foreach( var contentToClose in Layout.Descendents().OfType().Where( d => ( d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow ) ).ToArray() ) - { - this.Close( contentToClose ); - } + ( documentToRemove.Parent as ILayoutContainer ).RemoveChild( + documentToRemove ); + this.RemoveViewFromLogicalChild( documentToRemove ); } + } - private void Close( LayoutContent contentToClose ) - { - if( !contentToClose.CanClose ) - return; + if( Layout != null ) + { + Layout.CollectGarbage(); + } + } - var layoutItem = GetLayoutItemFromModel( contentToClose ); - if( layoutItem.CloseCommand != null ) - { - if( layoutItem.CloseCommand.CanExecute( null ) ) - layoutItem.CloseCommand.Execute( null ); - } - else - { - if( contentToClose is LayoutDocument ) - _ExecuteCloseCommand( contentToClose as LayoutDocument ); - else if( contentToClose is LayoutAnchorable ) - _ExecuteCloseCommand( contentToClose as LayoutAnchorable ); - } - } + void DetachDocumentsSource( LayoutRoot layout, IEnumerable documentsSource ) + { + if( documentsSource == null ) + return; - #region DocumentContextMenu + if( layout == null ) + return; - /// - /// DocumentContextMenu Dependency Property - /// - public static readonly DependencyProperty DocumentContextMenuProperty = - DependencyProperty.Register("DocumentContextMenu", typeof(ContextMenu), typeof(DockingManager), - new FrameworkPropertyMetadata((ContextMenu)null)); + var documentsToRemove = layout.Descendents().OfType() + .Where( d => documentsSource.Contains( d.Content ) ).ToArray(); - /// - /// Gets or sets the DocumentContextMenu property. This dependency property - /// indicates context menu to show for documents. - /// - public ContextMenu DocumentContextMenu - { - get { return (ContextMenu)GetValue(DocumentContextMenuProperty); } - set { SetValue(DocumentContextMenuProperty, value); } - } + foreach( var documentToRemove in documentsToRemove ) + { + ( documentToRemove.Parent as ILayoutContainer ).RemoveChild( + documentToRemove ); + this.RemoveViewFromLogicalChild( documentToRemove ); + } - #endregion + var documentsSourceAsNotifier = documentsSource as INotifyCollectionChanged; + if( documentsSourceAsNotifier != null ) + documentsSourceAsNotifier.CollectionChanged -= new NotifyCollectionChangedEventHandler( documentsSourceElementsChanged ); + } - #region AnchorablesSource - /// - /// AnchorablesSource Dependency Property - /// - public static readonly DependencyProperty AnchorablesSourceProperty = - DependencyProperty.Register("AnchorablesSource", typeof(IEnumerable), typeof(DockingManager), - new FrameworkPropertyMetadata((IEnumerable)null, - new PropertyChangedCallback(OnAnchorablesSourceChanged))); + #endregion - /// - /// Gets or sets the AnchorablesSource property. This dependency property - /// indicates source collection of anchorables. - /// - public IEnumerable AnchorablesSource - { - get { return (IEnumerable)GetValue(AnchorablesSourceProperty); } - set { SetValue(AnchorablesSourceProperty, value); } - } + #region DocumentCloseCommand - /// - /// Handles changes to the AnchorablesSource property. - /// - private static void OnAnchorablesSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnAnchorablesSourceChanged(e); - } + internal void _ExecuteCloseCommand( LayoutDocument document ) + { + if( DocumentClosing != null ) + { + var evargs = new DocumentClosingEventArgs( document ); + DocumentClosing( this, evargs ); + if( evargs.Cancel ) + return; + } + + if( document.CloseDocument() ) + { + this.RemoveViewFromLogicalChild( document ); - /// - /// Provides derived classes an opportunity to handle changes to the AnchorablesSource property. - /// - protected virtual void OnAnchorablesSourceChanged(DependencyPropertyChangedEventArgs e) + if( DocumentClosed != null ) { - DetachAnchorablesSource(Layout, e.OldValue as IEnumerable); - AttachAnchorablesSource(Layout, e.NewValue as IEnumerable); + var evargs = new DocumentClosedEventArgs( document ); + DocumentClosed( this, evargs ); } + } + } - void AttachAnchorablesSource(LayoutRoot layout, IEnumerable anchorablesSource) - { - if (anchorablesSource == null) - return; + /// + /// Event fired when a document is about to be closed + /// + /// Subscribers have the opportuniy to cancel the operation. + public event EventHandler DocumentClosing; - if (layout == null) - return; + /// + /// Event fired after a document is closed + /// + public event EventHandler DocumentClosed; - //if (layout.Descendents().OfType().Any()) - // throw new InvalidOperationException("Unable to set the AnchorablesSource property if LayoutAnchorable objects are already present in the model"); - var anchorablesImported = layout.Descendents().OfType().Select(d => d.Content).ToArray(); - var anchorables = anchorablesSource as IEnumerable; - var listOfAnchorablesToImport = new List(anchorables.OfType()); - foreach (var document in listOfAnchorablesToImport.ToArray()) - { - if (anchorablesImported.Contains(document)) - listOfAnchorablesToImport.Remove(document); - } - LayoutAnchorablePane anchorablePane = null; - if (layout.ActiveContent != null) - { - //look for active content parent pane - anchorablePane = layout.ActiveContent.Parent as LayoutAnchorablePane; - } + #endregion - if (anchorablePane == null) - { - //look for a pane on the right side - anchorablePane = layout.Descendents().OfType().Where(pane => !pane.IsHostedInFloatingWindow && pane.GetSide() == AnchorSide.Right).FirstOrDefault(); - } + internal void _ExecuteCloseAllButThisCommand( LayoutContent contentSelected ) + { + foreach( var contentToClose in Layout.Descendents().OfType().Where( d => d != contentSelected && ( d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow ) ).ToArray() ) + { + this.Close( contentToClose ); + } + } - if (anchorablePane == null) - { - //look for an available pane - anchorablePane = layout.Descendents().OfType().FirstOrDefault(); - } + internal void _ExecuteCloseAllCommand( LayoutContent contentSelected ) + { + foreach( var contentToClose in Layout.Descendents().OfType().Where( d => ( d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow ) ).ToArray() ) + { + this.Close( contentToClose ); + } + } - _suspendLayoutItemCreation = true; - foreach (var anchorableContentToImport in listOfAnchorablesToImport) - { - var anchorableToImport = new LayoutAnchorable() - { - Content = anchorableContentToImport - }; + private void Close( LayoutContent contentToClose ) + { + if( !contentToClose.CanClose ) + return; - bool added = false; - if (LayoutUpdateStrategy != null) - { - added = LayoutUpdateStrategy.BeforeInsertAnchorable(layout, anchorableToImport, anchorablePane); - } + var layoutItem = GetLayoutItemFromModel( contentToClose ); + if( layoutItem.CloseCommand != null ) + { + if( layoutItem.CloseCommand.CanExecute( null ) ) + layoutItem.CloseCommand.Execute( null ); + } + else + { + if( contentToClose is LayoutDocument ) + _ExecuteCloseCommand( contentToClose as LayoutDocument ); + else if( contentToClose is LayoutAnchorable ) + _ExecuteCloseCommand( contentToClose as LayoutAnchorable ); + } + } - if (!added) - { - if (anchorablePane == null) - { - var mainLayoutPanel = new LayoutPanel() { Orientation = Orientation.Horizontal }; - if (layout.RootPanel != null) - { - mainLayoutPanel.Children.Add(layout.RootPanel); - } - - layout.RootPanel = mainLayoutPanel; - anchorablePane = new LayoutAnchorablePane() { DockWidth = new GridLength(200.0, GridUnitType.Pixel) }; - mainLayoutPanel.Children.Add(anchorablePane); - } + #region DocumentContextMenu - anchorablePane.Children.Add(anchorableToImport); - added = true; - } + /// + /// DocumentContextMenu Dependency Property + /// + public static readonly DependencyProperty DocumentContextMenuProperty = + DependencyProperty.Register( "DocumentContextMenu", typeof( ContextMenu ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( ContextMenu )null ) ); - if (LayoutUpdateStrategy != null) - LayoutUpdateStrategy.AfterInsertAnchorable(layout, anchorableToImport); + /// + /// Gets or sets the DocumentContextMenu property. This dependency property + /// indicates context menu to show for documents. + /// + public ContextMenu DocumentContextMenu + { + get + { + return ( ContextMenu )GetValue( DocumentContextMenuProperty ); + } + set + { + SetValue( DocumentContextMenuProperty, value ); + } + } + #endregion - CreateAnchorableLayoutItem(anchorableToImport); + #region AnchorablesSource - } + /// + /// AnchorablesSource Dependency Property + /// + public static readonly DependencyProperty AnchorablesSourceProperty = + DependencyProperty.Register( "AnchorablesSource", typeof( IEnumerable ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( IEnumerable )null, + new PropertyChangedCallback( OnAnchorablesSourceChanged ) ) ); - _suspendLayoutItemCreation = false; + /// + /// Gets or sets the AnchorablesSource property. This dependency property + /// indicates source collection of anchorables. + /// + public IEnumerable AnchorablesSource + { + get + { + return ( IEnumerable )GetValue( AnchorablesSourceProperty ); + } + set + { + SetValue( AnchorablesSourceProperty, value ); + } + } - var anchorablesSourceAsNotifier = anchorablesSource as INotifyCollectionChanged; - if (anchorablesSourceAsNotifier != null) - anchorablesSourceAsNotifier.CollectionChanged += new NotifyCollectionChangedEventHandler(anchorablesSourceElementsChanged); - } + /// + /// Handles changes to the AnchorablesSource property. + /// + private static void OnAnchorablesSourceChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnAnchorablesSourceChanged( e ); + } - internal bool SuspendAnchorablesSourceBinding = false; + /// + /// Provides derived classes an opportunity to handle changes to the AnchorablesSource property. + /// + protected virtual void OnAnchorablesSourceChanged( DependencyPropertyChangedEventArgs e ) + { + DetachAnchorablesSource( Layout, e.OldValue as IEnumerable ); + AttachAnchorablesSource( Layout, e.NewValue as IEnumerable ); + } - void anchorablesSourceElementsChanged(object sender, NotifyCollectionChangedEventArgs e) - { - if (Layout == null) - return; + void AttachAnchorablesSource( LayoutRoot layout, IEnumerable anchorablesSource ) + { + if( anchorablesSource == null ) + return; - //When deserializing documents are created automatically by the deserializer - if (SuspendAnchorablesSourceBinding) - return; + if( layout == null ) + return; - //handle remove - if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || - e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace) - { - if (e.OldItems != null) - { - var anchorablesToRemove = Layout.Descendents().OfType().Where(d => e.OldItems.Contains(d.Content)).ToArray(); - foreach (var anchorableToRemove in anchorablesToRemove) - { - anchorableToRemove.Content = null; - (anchorableToRemove.Parent as ILayoutContainer).RemoveChild( - anchorableToRemove); - this.RemoveViewFromLogicalChild( anchorableToRemove ); - } - } - } + //if (layout.Descendents().OfType().Any()) + // throw new InvalidOperationException("Unable to set the AnchorablesSource property if LayoutAnchorable objects are already present in the model"); + var anchorablesImported = layout.Descendents().OfType().Select( d => d.Content ).ToArray(); + var anchorables = anchorablesSource as IEnumerable; + var listOfAnchorablesToImport = new List( anchorables.OfType() ); - //handle add - if (e.NewItems != null && - (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || - e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace)) - { - if (e.NewItems != null) - { - LayoutAnchorablePane anchorablePane = null; + foreach( var document in listOfAnchorablesToImport.ToArray() ) + { + if( anchorablesImported.Contains( document ) ) + listOfAnchorablesToImport.Remove( document ); + } - if (Layout.ActiveContent != null) - { - //look for active content parent pane - anchorablePane = Layout.ActiveContent.Parent as LayoutAnchorablePane; - } + LayoutAnchorablePane anchorablePane = null; + if( layout.ActiveContent != null ) + { + //look for active content parent pane + anchorablePane = layout.ActiveContent.Parent as LayoutAnchorablePane; + } - if (anchorablePane == null) - { - //look for a pane on the right side - anchorablePane = Layout.Descendents().OfType().Where(pane => !pane.IsHostedInFloatingWindow && pane.GetSide() == AnchorSide.Right).FirstOrDefault(); - } + if( anchorablePane == null ) + { + //look for a pane on the right side + anchorablePane = layout.Descendents().OfType().Where( pane => !pane.IsHostedInFloatingWindow && pane.GetSide() == AnchorSide.Right ).FirstOrDefault(); + } - if (anchorablePane == null) - { - //look for an available pane - anchorablePane = Layout.Descendents().OfType().FirstOrDefault(); - } + if( anchorablePane == null ) + { + //look for an available pane + anchorablePane = layout.Descendents().OfType().FirstOrDefault(); + } - _suspendLayoutItemCreation = true; - foreach (var anchorableContentToImport in e.NewItems) - { - var anchorableToImport = new LayoutAnchorable() - { - Content = anchorableContentToImport - }; - - bool added = false; - if (LayoutUpdateStrategy != null) - { - added = LayoutUpdateStrategy.BeforeInsertAnchorable(Layout, anchorableToImport, anchorablePane); - } - - if (!added) - { - if (anchorablePane == null) - { - var mainLayoutPanel = new LayoutPanel() { Orientation = Orientation.Horizontal }; - if (Layout.RootPanel != null) - { - mainLayoutPanel.Children.Add(Layout.RootPanel); - } - - Layout.RootPanel = mainLayoutPanel; - anchorablePane = new LayoutAnchorablePane() { DockWidth = new GridLength(200.0, GridUnitType.Pixel) }; - mainLayoutPanel.Children.Add(anchorablePane); - } - - anchorablePane.Children.Add(anchorableToImport); - added = true; - } - - if (LayoutUpdateStrategy != null) - { - LayoutUpdateStrategy.AfterInsertAnchorable(Layout, anchorableToImport); - } - - var root = anchorableToImport.Root; - - if (root != null && root.Manager == this) - { - CreateAnchorableLayoutItem(anchorableToImport); - } + _suspendLayoutItemCreation = true; + foreach( var anchorableContentToImport in listOfAnchorablesToImport ) + { + var anchorableToImport = new LayoutAnchorable() + { + Content = anchorableContentToImport + }; - } - _suspendLayoutItemCreation = false; - } - } + bool added = false; + if( LayoutUpdateStrategy != null ) + { + added = LayoutUpdateStrategy.BeforeInsertAnchorable( layout, anchorableToImport, anchorablePane ); + } - if (e.Action == NotifyCollectionChangedAction.Reset) + if( !added ) + { + if( anchorablePane == null ) + { + var mainLayoutPanel = new LayoutPanel() { Orientation = Orientation.Horizontal }; + if( layout.RootPanel != null ) { - //NOTE: I'm going to clear every anchorable present in layout but - //some anchorable may have been added directly to the layout, for now I clear them too - var anchorablesToRemove = Layout.Descendents().OfType().ToArray(); - foreach (var anchorableToRemove in anchorablesToRemove) - { - (anchorableToRemove.Parent as ILayoutContainer).RemoveChild( - anchorableToRemove); - this.RemoveViewFromLogicalChild( anchorableToRemove ); - } + mainLayoutPanel.Children.Add( layout.RootPanel ); } - if (Layout != null) - Layout.CollectGarbage(); + layout.RootPanel = mainLayoutPanel; + anchorablePane = new LayoutAnchorablePane() { DockWidth = new GridLength( 200.0, GridUnitType.Pixel ) }; + mainLayoutPanel.Children.Add( anchorablePane ); + } + + anchorablePane.Children.Add( anchorableToImport ); + added = true; } - void DetachAnchorablesSource(LayoutRoot layout, IEnumerable anchorablesSource) - { - if (anchorablesSource == null) - return; + if( LayoutUpdateStrategy != null ) + LayoutUpdateStrategy.AfterInsertAnchorable( layout, anchorableToImport ); - if (layout == null) - return; - var anchorablesToRemove = layout.Descendents().OfType() - .Where(d => anchorablesSource.Contains(d.Content)).ToArray(); + CreateAnchorableLayoutItem( anchorableToImport ); - foreach (var anchorableToRemove in anchorablesToRemove) - { - (anchorableToRemove.Parent as ILayoutContainer).RemoveChild( - anchorableToRemove); - this.RemoveViewFromLogicalChild( anchorableToRemove ); - } + } - var anchorablesSourceAsNotifier = anchorablesSource as INotifyCollectionChanged; - if (anchorablesSourceAsNotifier != null) - anchorablesSourceAsNotifier.CollectionChanged -= new NotifyCollectionChangedEventHandler(anchorablesSourceElementsChanged); - } + _suspendLayoutItemCreation = false; + + var anchorablesSourceAsNotifier = anchorablesSource as INotifyCollectionChanged; + if( anchorablesSourceAsNotifier != null ) + anchorablesSourceAsNotifier.CollectionChanged += new NotifyCollectionChangedEventHandler( anchorablesSourceElementsChanged ); + } + + internal bool SuspendAnchorablesSourceBinding = false; - #endregion + void anchorablesSourceElementsChanged( object sender, NotifyCollectionChangedEventArgs e ) + { + if( Layout == null ) + return; + + //When deserializing documents are created automatically by the deserializer + if( SuspendAnchorablesSourceBinding ) + return; - internal void _ExecuteCloseCommand(LayoutAnchorable anchorable) + //handle remove + if( e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace ) + { + if( e.OldItems != null ) { - var model = anchorable as LayoutAnchorable; - if (model != null ) - { - model.CloseAnchorable(); - this.RemoveViewFromLogicalChild( anchorable ); - } + var anchorablesToRemove = Layout.Descendents().OfType().Where( d => e.OldItems.Contains( d.Content ) ).ToArray(); + foreach( var anchorableToRemove in anchorablesToRemove ) + { + anchorableToRemove.Content = null; + ( anchorableToRemove.Parent as ILayoutContainer ).RemoveChild( + anchorableToRemove ); + this.RemoveViewFromLogicalChild( anchorableToRemove ); + } } + } - internal void _ExecuteHideCommand(LayoutAnchorable anchorable) + //handle add + if( e.NewItems != null && + ( e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace ) ) + { + if( e.NewItems != null ) { - var model = anchorable as LayoutAnchorable; - if (model != null) + LayoutAnchorablePane anchorablePane = null; + + if( Layout.ActiveContent != null ) + { + //look for active content parent pane + anchorablePane = Layout.ActiveContent.Parent as LayoutAnchorablePane; + } + + if( anchorablePane == null ) + { + //look for a pane on the right side + anchorablePane = Layout.Descendents().OfType().Where( pane => !pane.IsHostedInFloatingWindow && pane.GetSide() == AnchorSide.Right ).FirstOrDefault(); + } + + if( anchorablePane == null ) + { + //look for an available pane + anchorablePane = Layout.Descendents().OfType().FirstOrDefault(); + } + + _suspendLayoutItemCreation = true; + foreach( var anchorableContentToImport in e.NewItems ) + { + var anchorableToImport = new LayoutAnchorable() { - //by default hide the anchorable - model.Hide(); + Content = anchorableContentToImport + }; + + bool added = false; + if( LayoutUpdateStrategy != null ) + { + added = LayoutUpdateStrategy.BeforeInsertAnchorable( Layout, anchorableToImport, anchorablePane ); } - } - internal void _ExecuteAutoHideCommand(LayoutAnchorable _anchorable) - { - _anchorable.ToggleAutoHide(); - } + if( !added ) + { + if( anchorablePane == null ) + { + var mainLayoutPanel = new LayoutPanel() { Orientation = Orientation.Horizontal }; + if( Layout.RootPanel != null ) + { + mainLayoutPanel.Children.Add( Layout.RootPanel ); + } - internal void _ExecuteFloatCommand(LayoutContent contentToFloat) - { - contentToFloat.Float(); - } + Layout.RootPanel = mainLayoutPanel; + anchorablePane = new LayoutAnchorablePane() { DockWidth = new GridLength( 200.0, GridUnitType.Pixel ) }; + mainLayoutPanel.Children.Add( anchorablePane ); + } - internal void _ExecuteDockCommand(LayoutAnchorable anchorable) - { - anchorable.Dock(); - } + anchorablePane.Children.Add( anchorableToImport ); + added = true; + } - internal void _ExecuteDockAsDocumentCommand(LayoutContent content) - { - content.DockAsDocument(); - } + if( LayoutUpdateStrategy != null ) + { + LayoutUpdateStrategy.AfterInsertAnchorable( Layout, anchorableToImport ); + } - private void RemoveViewFromLogicalChild( LayoutContent layoutContent ) - { - if( layoutContent == null ) - return; + var root = anchorableToImport.Root; - var layoutItem = this.GetLayoutItemFromModel( layoutContent ); - if( layoutItem != null ) - { - if( layoutItem.IsViewExists() ) + if( root != null && root.Manager == this ) { - this.InternalRemoveLogicalChild( layoutItem.View ); + CreateAnchorableLayoutItem( anchorableToImport ); } + } + _suspendLayoutItemCreation = false; } + } - #region ActiveContent - - /// - /// ActiveContent Dependency Property - /// - public static readonly DependencyProperty ActiveContentProperty = - DependencyProperty.Register("ActiveContent", typeof(object), typeof(DockingManager), - new FrameworkPropertyMetadata((object)null, - new PropertyChangedCallback(OnActiveContentChanged))); - - /// - /// Gets or sets the ActiveContent property. This dependency property - /// indicates the content currently active. - /// - public object ActiveContent + if( e.Action == NotifyCollectionChangedAction.Reset ) + { + //NOTE: I'm going to clear every anchorable present in layout but + //some anchorable may have been added directly to the layout, for now I clear them too + var anchorablesToRemove = Layout.Descendents().OfType().ToArray(); + foreach( var anchorableToRemove in anchorablesToRemove ) { - get { return (object)GetValue(ActiveContentProperty); } - set { SetValue(ActiveContentProperty, value); } + ( anchorableToRemove.Parent as ILayoutContainer ).RemoveChild( + anchorableToRemove ); + this.RemoveViewFromLogicalChild( anchorableToRemove ); } + } - /// - /// Handles changes to the ActiveContent property. - /// - private static void OnActiveContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).InternalSetActiveContent(e.NewValue); - ((DockingManager)d).OnActiveContentChanged(e); - } + if( Layout != null ) + Layout.CollectGarbage(); + } - /// - /// Provides derived classes an opportunity to handle changes to the ActiveContent property. - /// - protected virtual void OnActiveContentChanged(DependencyPropertyChangedEventArgs e) - { - if (ActiveContentChanged != null) - ActiveContentChanged(this, EventArgs.Empty); - } + void DetachAnchorablesSource( LayoutRoot layout, IEnumerable anchorablesSource ) + { + if( anchorablesSource == null ) + return; + if( layout == null ) + return; - bool _insideInternalSetActiveContent = false; - void InternalSetActiveContent(object contentObject) - { - var layoutContent = Layout.Descendents().OfType().FirstOrDefault(lc => lc == contentObject || lc.Content == contentObject); - _insideInternalSetActiveContent = true; - Layout.ActiveContent = layoutContent; - _insideInternalSetActiveContent = false; - } + var anchorablesToRemove = layout.Descendents().OfType() + .Where( d => anchorablesSource.Contains( d.Content ) ).ToArray(); - public event EventHandler ActiveContentChanged; + foreach( var anchorableToRemove in anchorablesToRemove ) + { + ( anchorableToRemove.Parent as ILayoutContainer ).RemoveChild( + anchorableToRemove ); + this.RemoveViewFromLogicalChild( anchorableToRemove ); + } - #endregion + var anchorablesSourceAsNotifier = anchorablesSource as INotifyCollectionChanged; + if( anchorablesSourceAsNotifier != null ) + anchorablesSourceAsNotifier.CollectionChanged -= new NotifyCollectionChangedEventHandler( anchorablesSourceElementsChanged ); + } - #region AnchorableContextMenu + #endregion - /// - /// AnchorableContextMenu Dependency Property - /// - public static readonly DependencyProperty AnchorableContextMenuProperty = - DependencyProperty.Register("AnchorableContextMenu", typeof(ContextMenu), typeof(DockingManager), - new FrameworkPropertyMetadata((ContextMenu)null)); + internal void _ExecuteCloseCommand( LayoutAnchorable anchorable ) + { + var model = anchorable as LayoutAnchorable; + if( model != null ) + { + model.CloseAnchorable(); + this.RemoveViewFromLogicalChild( anchorable ); + } + } - /// - /// Gets or sets the AnchorableContextMenu property. This dependency property - /// indicates the context menu to show up for anchorables. - /// - public ContextMenu AnchorableContextMenu - { - get { return (ContextMenu)GetValue(AnchorableContextMenuProperty); } - set { SetValue(AnchorableContextMenuProperty, value); } - } + internal void _ExecuteHideCommand( LayoutAnchorable anchorable ) + { + var model = anchorable as LayoutAnchorable; + if( model != null ) + { + model.Hide(); + } + } + + internal void _ExecuteAutoHideCommand( LayoutAnchorable _anchorable ) + { + _anchorable.ToggleAutoHide(); + } - #endregion + internal void _ExecuteFloatCommand( LayoutContent contentToFloat ) + { + contentToFloat.Float(); + } - #region Theme + internal void _ExecuteDockCommand( LayoutAnchorable anchorable ) + { + anchorable.Dock(); + } - /// - /// Theme Dependency Property - /// - public static readonly DependencyProperty ThemeProperty = - DependencyProperty.Register("Theme", typeof(Theme), typeof(DockingManager), - new FrameworkPropertyMetadata(null, - new PropertyChangedCallback(OnThemeChanged))); + internal void _ExecuteDockAsDocumentCommand( LayoutContent content ) + { + content.DockAsDocument(); + } - /// - /// Gets or sets the Theme property. This dependency property - /// indicates the theme to use for AvalonDock controls. - /// - public Theme Theme - { - get { return (Theme)GetValue(ThemeProperty); } - set { SetValue(ThemeProperty, value); } - } + private void RemoveViewFromLogicalChild( LayoutContent layoutContent ) + { + if( layoutContent == null ) + return; - /// - /// Handles changes to the Theme property. - /// - private static void OnThemeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + var layoutItem = this.GetLayoutItemFromModel( layoutContent ); + if( layoutItem != null ) + { + if( layoutItem.IsViewExists() ) { - ((DockingManager)d).OnThemeChanged(e); + this.InternalRemoveLogicalChild( layoutItem.View ); } + } + } - /// - /// Provides derived classes an opportunity to handle changes to the Theme property. - /// - protected virtual void OnThemeChanged(DependencyPropertyChangedEventArgs e) - { - var oldTheme = e.OldValue as Theme; - var newTheme = e.NewValue as Theme; - var resources = this.Resources; - if (oldTheme != null) - { - if( oldTheme is DictionaryTheme ) - { - if( currentThemeResourceDictionary != null ) - { - resources.MergedDictionaries.Remove( currentThemeResourceDictionary ); - currentThemeResourceDictionary = null; - } - } - else - { - var resourceDictionaryToRemove = - resources.MergedDictionaries.FirstOrDefault( r => r.Source == oldTheme.GetResourceUri() ); - if( resourceDictionaryToRemove != null ) - resources.MergedDictionaries.Remove( - resourceDictionaryToRemove ); - } - } + #region ActiveContent + + /// + /// ActiveContent Dependency Property + /// + public static readonly DependencyProperty ActiveContentProperty = + DependencyProperty.Register( "ActiveContent", typeof( object ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( object )null, + new PropertyChangedCallback( OnActiveContentChanged ) ) ); + + /// + /// Gets or sets the ActiveContent property. This dependency property + /// indicates the content currently active. + /// + public object ActiveContent + { + get + { + return ( object )GetValue( ActiveContentProperty ); + } + set + { + SetValue( ActiveContentProperty, value ); + } + } - if (newTheme != null) - { - if( newTheme is DictionaryTheme ) - { - currentThemeResourceDictionary = ( ( DictionaryTheme )newTheme ).ThemeResourceDictionary; - resources.MergedDictionaries.Add( currentThemeResourceDictionary ); - } - else - { - resources.MergedDictionaries.Add(new ResourceDictionary() { Source = newTheme.GetResourceUri() }); - } - } + /// + /// Handles changes to the ActiveContent property. + /// + private static void OnActiveContentChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).InternalSetActiveContent( e.NewValue ); + ( ( DockingManager )d ).OnActiveContentChanged( e ); + } + + /// + /// Provides derived classes an opportunity to handle changes to the ActiveContent property. + /// + protected virtual void OnActiveContentChanged( DependencyPropertyChangedEventArgs e ) + { + if( ActiveContentChanged != null ) + ActiveContentChanged( this, EventArgs.Empty ); + } + + + bool _insideInternalSetActiveContent = false; + void InternalSetActiveContent( object contentObject ) + { + var layoutContent = Layout.Descendents().OfType().FirstOrDefault( lc => lc == contentObject || lc.Content == contentObject ); + _insideInternalSetActiveContent = true; + Layout.ActiveContent = layoutContent; + _insideInternalSetActiveContent = false; + } - foreach (var fwc in _fwList) - fwc.UpdateThemeResources(oldTheme); + public event EventHandler ActiveContentChanged; - if (_navigatorWindow != null) - _navigatorWindow.UpdateThemeResources(); + #endregion - if (_overlayWindow != null) - _overlayWindow.UpdateThemeResources(); - } + #region AnchorableContextMenu - #endregion + /// + /// AnchorableContextMenu Dependency Property + /// + public static readonly DependencyProperty AnchorableContextMenuProperty = + DependencyProperty.Register( "AnchorableContextMenu", typeof( ContextMenu ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( ContextMenu )null ) ); - #region GridSplitterWidth + /// + /// Gets or sets the AnchorableContextMenu property. This dependency property + /// indicates the context menu to show up for anchorables. + /// + public ContextMenu AnchorableContextMenu + { + get + { + return ( ContextMenu )GetValue( AnchorableContextMenuProperty ); + } + set + { + SetValue( AnchorableContextMenuProperty, value ); + } + } - /// - /// GridSplitterWidth Dependency Property - /// - public static readonly DependencyProperty GridSplitterWidthProperty = - DependencyProperty.Register("GridSplitterWidth", typeof(double), typeof(DockingManager), - new FrameworkPropertyMetadata((double)6.0)); + #endregion - /// - /// Gets or sets the GridSplitterWidth property. This dependency property - /// indicates width of grid splitters. - /// - public double GridSplitterWidth - { - get { return (double)GetValue(GridSplitterWidthProperty); } - set { SetValue(GridSplitterWidthProperty, value); } - } + #region Theme - #endregion + /// + /// Theme Dependency Property + /// + public static readonly DependencyProperty ThemeProperty = + DependencyProperty.Register( "Theme", typeof( Theme ), typeof( DockingManager ), + new FrameworkPropertyMetadata( null, + new PropertyChangedCallback( OnThemeChanged ) ) ); - #region GridSplitterHeight + /// + /// Gets or sets the Theme property. This dependency property + /// indicates the theme to use for AvalonDock controls. + /// + public Theme Theme + { + get + { + return ( Theme )GetValue( ThemeProperty ); + } + set + { + SetValue( ThemeProperty, value ); + } + } - /// - /// GridSplitterHeight Dependency Property - /// - public static readonly DependencyProperty GridSplitterHeightProperty = - DependencyProperty.Register("GridSplitterHeight", typeof(double), typeof(DockingManager), - new FrameworkPropertyMetadata((double)6.0)); + /// + /// Handles changes to the Theme property. + /// + private static void OnThemeChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnThemeChanged( e ); + } - /// - /// Gets or sets the GridSplitterHeight property. This dependency property - /// indicates height of grid splitters. - /// - public double GridSplitterHeight + /// + /// Provides derived classes an opportunity to handle changes to the Theme property. + /// + protected virtual void OnThemeChanged( DependencyPropertyChangedEventArgs e ) + { + var oldTheme = e.OldValue as Theme; + var newTheme = e.NewValue as Theme; + var resources = this.Resources; + if( oldTheme != null ) + { + if( oldTheme is DictionaryTheme ) { - get { return (double)GetValue(GridSplitterHeightProperty); } - set { SetValue(GridSplitterHeightProperty, value); } + if( currentThemeResourceDictionary != null ) + { + resources.MergedDictionaries.Remove( currentThemeResourceDictionary ); + currentThemeResourceDictionary = null; + } } - - #endregion - - internal void _ExecuteContentActivateCommand(LayoutContent content) + else { - content.IsActive = true; + var resourceDictionaryToRemove = + resources.MergedDictionaries.FirstOrDefault( r => r.Source == oldTheme.GetResourceUri() ); + if( resourceDictionaryToRemove != null ) + resources.MergedDictionaries.Remove( + resourceDictionaryToRemove ); } + } - #region DocumentPaneMenuItemHeaderTemplate - - /// - /// DocumentPaneMenuItemHeaderTemplate Dependency Property - /// - public static readonly DependencyProperty DocumentPaneMenuItemHeaderTemplateProperty = - DependencyProperty.Register("DocumentPaneMenuItemHeaderTemplate", typeof(DataTemplate), typeof(DockingManager), - new FrameworkPropertyMetadata((DataTemplate)null, - new PropertyChangedCallback(OnDocumentPaneMenuItemHeaderTemplateChanged), - new CoerceValueCallback(CoerceDocumentPaneMenuItemHeaderTemplateValue))); - - /// - /// Gets or sets the DocumentPaneMenuItemHeaderTemplate property. This dependency property - /// indicates the header template to use while creating menu items for the document panes. - /// - public DataTemplate DocumentPaneMenuItemHeaderTemplate + if( newTheme != null ) + { + if( newTheme is DictionaryTheme ) { - get { return (DataTemplate)GetValue(DocumentPaneMenuItemHeaderTemplateProperty); } - set { SetValue(DocumentPaneMenuItemHeaderTemplateProperty, value); } + currentThemeResourceDictionary = ( ( DictionaryTheme )newTheme ).ThemeResourceDictionary; + resources.MergedDictionaries.Add( currentThemeResourceDictionary ); } - - /// - /// Handles changes to the DocumentPaneMenuItemHeaderTemplate property. - /// - private static void OnDocumentPaneMenuItemHeaderTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + else { - ((DockingManager)d).OnDocumentPaneMenuItemHeaderTemplateChanged(e); + resources.MergedDictionaries.Add( new ResourceDictionary() { Source = newTheme.GetResourceUri() } ); } + } - /// - /// Provides derived classes an opportunity to handle changes to the DocumentPaneMenuItemHeaderTemplate property. - /// - protected virtual void OnDocumentPaneMenuItemHeaderTemplateChanged(DependencyPropertyChangedEventArgs e) - { - } + foreach( var fwc in _fwList ) + fwc.UpdateThemeResources( oldTheme ); - /// - /// Coerces the DocumentPaneMenuItemHeaderTemplate value. - /// - private static object CoerceDocumentPaneMenuItemHeaderTemplateValue(DependencyObject d, object value) - { - if (value != null && - d.GetValue(DocumentPaneMenuItemHeaderTemplateSelectorProperty) != null) - return null; - if (value == null) - return d.GetValue(DocumentHeaderTemplateProperty); + if( _navigatorWindow != null ) + _navigatorWindow.UpdateThemeResources(); - return value; - } + if( _overlayWindow != null ) + _overlayWindow.UpdateThemeResources(); + } - #endregion + #endregion - #region DocumentPaneMenuItemHeaderTemplateSelector + #region GridSplitterWidth - /// - /// DocumentPaneMenuItemHeaderTemplateSelector Dependency Property - /// - public static readonly DependencyProperty DocumentPaneMenuItemHeaderTemplateSelectorProperty = - DependencyProperty.Register("DocumentPaneMenuItemHeaderTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), - new FrameworkPropertyMetadata((DataTemplateSelector)null, - new PropertyChangedCallback(OnDocumentPaneMenuItemHeaderTemplateSelectorChanged), - new CoerceValueCallback(CoerceDocumentPaneMenuItemHeaderTemplateSelectorValue))); + /// + /// GridSplitterWidth Dependency Property + /// + public static readonly DependencyProperty GridSplitterWidthProperty = + DependencyProperty.Register( "GridSplitterWidth", typeof( double ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( double )6.0 ) ); - /// - /// Gets or sets the DocumentPaneMenuItemHeaderTemplateSelector property. This dependency property - /// indicates the data template selector to use for the menu items show when user select the DocumentPane document switch context menu. - /// - public DataTemplateSelector DocumentPaneMenuItemHeaderTemplateSelector - { - get { return (DataTemplateSelector)GetValue(DocumentPaneMenuItemHeaderTemplateSelectorProperty); } - set { SetValue(DocumentPaneMenuItemHeaderTemplateSelectorProperty, value); } - } + /// + /// Gets or sets the GridSplitterWidth property. This dependency property + /// indicates width of grid splitters. + /// + public double GridSplitterWidth + { + get + { + return ( double )GetValue( GridSplitterWidthProperty ); + } + set + { + SetValue( GridSplitterWidthProperty, value ); + } + } - /// - /// Handles changes to the DocumentPaneMenuItemHeaderTemplateSelector property. - /// - private static void OnDocumentPaneMenuItemHeaderTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnDocumentPaneMenuItemHeaderTemplateSelectorChanged(e); - } + #endregion - /// - /// Provides derived classes an opportunity to handle changes to the DocumentPaneMenuItemHeaderTemplateSelector property. - /// - protected virtual void OnDocumentPaneMenuItemHeaderTemplateSelectorChanged(DependencyPropertyChangedEventArgs e) - { - if (e.NewValue != null && - DocumentPaneMenuItemHeaderTemplate != null) - DocumentPaneMenuItemHeaderTemplate = null; + #region GridSplitterHeight - } + /// + /// GridSplitterHeight Dependency Property + /// + public static readonly DependencyProperty GridSplitterHeightProperty = + DependencyProperty.Register( "GridSplitterHeight", typeof( double ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( double )6.0 ) ); - /// - /// Coerces the DocumentPaneMenuItemHeaderTemplateSelector value. - /// - private static object CoerceDocumentPaneMenuItemHeaderTemplateSelectorValue(DependencyObject d, object value) - { - return value; - } + /// + /// Gets or sets the GridSplitterHeight property. This dependency property + /// indicates height of grid splitters. + /// + public double GridSplitterHeight + { + get + { + return ( double )GetValue( GridSplitterHeightProperty ); + } + set + { + SetValue( GridSplitterHeightProperty, value ); + } + } - #endregion + #endregion - #region IconContentTemplate + internal void _ExecuteContentActivateCommand( LayoutContent content ) + { + content.IsActive = true; + } - /// - /// IconContentTemplate Dependency Property - /// - public static readonly DependencyProperty IconContentTemplateProperty = - DependencyProperty.Register("IconContentTemplate", typeof(DataTemplate), typeof(DockingManager), - new FrameworkPropertyMetadata((DataTemplate)null)); + #region DocumentPaneMenuItemHeaderTemplate + + /// + /// DocumentPaneMenuItemHeaderTemplate Dependency Property + /// + public static readonly DependencyProperty DocumentPaneMenuItemHeaderTemplateProperty = + DependencyProperty.Register( "DocumentPaneMenuItemHeaderTemplate", typeof( DataTemplate ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( DataTemplate )null, + new PropertyChangedCallback( OnDocumentPaneMenuItemHeaderTemplateChanged ), + new CoerceValueCallback( CoerceDocumentPaneMenuItemHeaderTemplateValue ) ) ); + + /// + /// Gets or sets the DocumentPaneMenuItemHeaderTemplate property. This dependency property + /// indicates the header template to use while creating menu items for the document panes. + /// + public DataTemplate DocumentPaneMenuItemHeaderTemplate + { + get + { + return ( DataTemplate )GetValue( DocumentPaneMenuItemHeaderTemplateProperty ); + } + set + { + SetValue( DocumentPaneMenuItemHeaderTemplateProperty, value ); + } + } - /// - /// Gets or sets the IconContentTemplate property. This dependency property - /// indicates the data template to use while extracting the icon from model. - /// - public DataTemplate IconContentTemplate - { - get { return (DataTemplate)GetValue(IconContentTemplateProperty); } - set { SetValue(IconContentTemplateProperty, value); } - } + /// + /// Handles changes to the DocumentPaneMenuItemHeaderTemplate property. + /// + private static void OnDocumentPaneMenuItemHeaderTemplateChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnDocumentPaneMenuItemHeaderTemplateChanged( e ); + } - #endregion + /// + /// Provides derived classes an opportunity to handle changes to the DocumentPaneMenuItemHeaderTemplate property. + /// + protected virtual void OnDocumentPaneMenuItemHeaderTemplateChanged( DependencyPropertyChangedEventArgs e ) + { + } - #region IconContentTemplateSelector + /// + /// Coerces the DocumentPaneMenuItemHeaderTemplate value. + /// + private static object CoerceDocumentPaneMenuItemHeaderTemplateValue( DependencyObject d, object value ) + { + if( value != null && + d.GetValue( DocumentPaneMenuItemHeaderTemplateSelectorProperty ) != null ) + return null; + if( value == null ) + return d.GetValue( DocumentHeaderTemplateProperty ); - /// - /// IconContentTemplateSelector Dependency Property - /// - public static readonly DependencyProperty IconContentTemplateSelectorProperty = - DependencyProperty.Register("IconContentTemplateSelector", typeof(DataTemplateSelector), typeof(DockingManager), - new FrameworkPropertyMetadata((DataTemplateSelector)null)); + return value; + } - /// - /// Gets or sets the IconContentTemplateSelector property. This dependency property - /// indicates data template selector to use while selecting the datatamplate for content icons. - /// - public DataTemplateSelector IconContentTemplateSelector - { - get { return (DataTemplateSelector)GetValue(IconContentTemplateSelectorProperty); } - set { SetValue(IconContentTemplateSelectorProperty, value); } - } + #endregion - #endregion + #region DocumentPaneMenuItemHeaderTemplateSelector - #region LayoutItems + /// + /// DocumentPaneMenuItemHeaderTemplateSelector Dependency Property + /// + public static readonly DependencyProperty DocumentPaneMenuItemHeaderTemplateSelectorProperty = + DependencyProperty.Register( "DocumentPaneMenuItemHeaderTemplateSelector", typeof( DataTemplateSelector ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( DataTemplateSelector )null, + new PropertyChangedCallback( OnDocumentPaneMenuItemHeaderTemplateSelectorChanged ), + new CoerceValueCallback( CoerceDocumentPaneMenuItemHeaderTemplateSelectorValue ) ) ); - List _layoutItems = new List(); + /// + /// Gets or sets the DocumentPaneMenuItemHeaderTemplateSelector property. This dependency property + /// indicates the data template selector to use for the menu items show when user select the DocumentPane document switch context menu. + /// + public DataTemplateSelector DocumentPaneMenuItemHeaderTemplateSelector + { + get + { + return ( DataTemplateSelector )GetValue( DocumentPaneMenuItemHeaderTemplateSelectorProperty ); + } + set + { + SetValue( DocumentPaneMenuItemHeaderTemplateSelectorProperty, value ); + } + } - bool _suspendLayoutItemCreation = false; + /// + /// Handles changes to the DocumentPaneMenuItemHeaderTemplateSelector property. + /// + private static void OnDocumentPaneMenuItemHeaderTemplateSelectorChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnDocumentPaneMenuItemHeaderTemplateSelectorChanged( e ); + } - void DetachLayoutItems() - { - if (Layout != null) - { - _layoutItems.ForEach(i => i.Detach()); - _layoutItems.Clear(); - Layout.ElementAdded -= new EventHandler(Layout_ElementAdded); - Layout.ElementRemoved -= new EventHandler(Layout_ElementRemoved); - } - } + /// + /// Provides derived classes an opportunity to handle changes to the DocumentPaneMenuItemHeaderTemplateSelector property. + /// + protected virtual void OnDocumentPaneMenuItemHeaderTemplateSelectorChanged( DependencyPropertyChangedEventArgs e ) + { + if( e.NewValue != null && + DocumentPaneMenuItemHeaderTemplate != null ) + DocumentPaneMenuItemHeaderTemplate = null; - void Layout_ElementRemoved(object sender, LayoutElementEventArgs e) - { - if (_suspendLayoutItemCreation) - return; + } - CollectLayoutItemsDeleted(); - } + /// + /// Coerces the DocumentPaneMenuItemHeaderTemplateSelector value. + /// + private static object CoerceDocumentPaneMenuItemHeaderTemplateSelectorValue( DependencyObject d, object value ) + { + return value; + } - void Layout_ElementAdded(object sender, LayoutElementEventArgs e) - { - if (_suspendLayoutItemCreation) - return; + #endregion - foreach (var content in Layout.Descendents().OfType()) - { - if (content is LayoutDocument) - CreateDocumentLayoutItem(content as LayoutDocument); - else //if (content is LayoutAnchorable) - CreateAnchorableLayoutItem(content as LayoutAnchorable); - } + #region IconContentTemplate - CollectLayoutItemsDeleted(); - } + /// + /// IconContentTemplate Dependency Property + /// + public static readonly DependencyProperty IconContentTemplateProperty = + DependencyProperty.Register( "IconContentTemplate", typeof( DataTemplate ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( DataTemplate )null ) ); + /// + /// Gets or sets the IconContentTemplate property. This dependency property + /// indicates the data template to use while extracting the icon from model. + /// + public DataTemplate IconContentTemplate + { + get + { + return ( DataTemplate )GetValue( IconContentTemplateProperty ); + } + set + { + SetValue( IconContentTemplateProperty, value ); + } + } - DispatcherOperation _collectLayoutItemsOperations = null; - void CollectLayoutItemsDeleted() - { - if (_collectLayoutItemsOperations != null) - return; - _collectLayoutItemsOperations = Dispatcher.BeginInvoke(new Action(() => - { - _collectLayoutItemsOperations = null; - foreach (var itemToRemove in _layoutItems.Where(item => item.LayoutElement.Root != Layout).ToArray()) - { + #endregion - if (itemToRemove != null && - itemToRemove.Model != null && - itemToRemove.Model is UIElement) - { - //((ILogicalChildrenContainer)this).InternalRemoveLogicalChild(itemToRemove.Model as UIElement); - } + #region IconContentTemplateSelector - itemToRemove.Detach(); - _layoutItems.Remove(itemToRemove); + /// + /// IconContentTemplateSelector Dependency Property + /// + public static readonly DependencyProperty IconContentTemplateSelectorProperty = + DependencyProperty.Register( "IconContentTemplateSelector", typeof( DataTemplateSelector ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( DataTemplateSelector )null ) ); - } - })); - } + /// + /// Gets or sets the IconContentTemplateSelector property. This dependency property + /// indicates data template selector to use while selecting the datatamplate for content icons. + /// + public DataTemplateSelector IconContentTemplateSelector + { + get + { + return ( DataTemplateSelector )GetValue( IconContentTemplateSelectorProperty ); + } + set + { + SetValue( IconContentTemplateSelectorProperty, value ); + } + } + #endregion - void AttachLayoutItems() - { - if (Layout != null) - { - foreach (var document in Layout.Descendents().OfType().ToArray()) - { - CreateDocumentLayoutItem(document); - //var documentItem = new LayoutDocumentItem(); - //documentItem.Attach(document); - //ApplyStyleToLayoutItem(documentItem); - //_layoutItems.Add(documentItem); - } - foreach (var anchorable in Layout.Descendents().OfType().ToArray()) - { - CreateAnchorableLayoutItem(anchorable); - //var anchorableItem = new LayoutAnchorableItem(); - //anchorableItem.Attach(anchorable); - //ApplyStyleToLayoutItem(anchorableItem); - //_layoutItems.Add(anchorableItem); - } + #region LayoutItems - Layout.ElementAdded += new EventHandler(Layout_ElementAdded); - Layout.ElementRemoved += new EventHandler(Layout_ElementRemoved); - } - } + List _layoutItems = new List(); - void ApplyStyleToLayoutItem(LayoutItem layoutItem) - { - layoutItem._ClearDefaultBindings(); - if (LayoutItemContainerStyle != null) - layoutItem.Style = LayoutItemContainerStyle; - else if (LayoutItemContainerStyleSelector != null) - layoutItem.Style = LayoutItemContainerStyleSelector.SelectStyle(layoutItem.Model, layoutItem); - layoutItem._SetDefaultBindings(); - } + bool _suspendLayoutItemCreation = false; - void CreateAnchorableLayoutItem(LayoutAnchorable contentToAttach) - { - if (_layoutItems.Any(item => item.LayoutElement == contentToAttach)) - return; + void DetachLayoutItems() + { + if( Layout != null ) + { + _layoutItems.ForEach( i => i.Detach() ); + _layoutItems.Clear(); + Layout.ElementAdded -= new EventHandler( Layout_ElementAdded ); + Layout.ElementRemoved -= new EventHandler( Layout_ElementRemoved ); + } + } - var layoutItem = new LayoutAnchorableItem(); - layoutItem.Attach(contentToAttach); - ApplyStyleToLayoutItem(layoutItem); - _layoutItems.Add(layoutItem); + void Layout_ElementRemoved( object sender, LayoutElementEventArgs e ) + { + if( _suspendLayoutItemCreation ) + return; - if (contentToAttach != null && - contentToAttach.Content != null && - contentToAttach.Content is UIElement) - { - InternalAddLogicalChild(contentToAttach.Content); - } + CollectLayoutItemsDeleted(); + } - } + void Layout_ElementAdded( object sender, LayoutElementEventArgs e ) + { + if( _suspendLayoutItemCreation ) + return; - void CreateDocumentLayoutItem(LayoutDocument contentToAttach) - { - if (_layoutItems.Any(item => item.LayoutElement == contentToAttach)) - return; + foreach( var content in Layout.Descendents().OfType() ) + { + if( content is LayoutDocument ) + CreateDocumentLayoutItem( content as LayoutDocument ); + else //if (content is LayoutAnchorable) + CreateAnchorableLayoutItem( content as LayoutAnchorable ); + } + + CollectLayoutItemsDeleted(); + } - var layoutItem = new LayoutDocumentItem(); - layoutItem.Attach(contentToAttach); - ApplyStyleToLayoutItem(layoutItem); - _layoutItems.Add(layoutItem); - if (contentToAttach != null && - contentToAttach.Content != null && - contentToAttach.Content is UIElement) + DispatcherOperation _collectLayoutItemsOperations = null; + void CollectLayoutItemsDeleted() + { + if( _collectLayoutItemsOperations != null ) + return; + _collectLayoutItemsOperations = Dispatcher.BeginInvoke( new Action( () => { - InternalAddLogicalChild(contentToAttach.Content); - } + _collectLayoutItemsOperations = null; + foreach( var itemToRemove in _layoutItems.Where( item => item.LayoutElement.Root != Layout ).ToArray() ) + { - } + if( itemToRemove != null && + itemToRemove.Model != null && + itemToRemove.Model is UIElement ) + { + //((ILogicalChildrenContainer)this).InternalRemoveLogicalChild(itemToRemove.Model as UIElement); + } + + itemToRemove.Detach(); + _layoutItems.Remove( itemToRemove ); + + } + } ) ); + } - #region LayoutItemContainerStyle - - /// - /// LayoutItemContainerStyle Dependency Property - /// - public static readonly DependencyProperty LayoutItemContainerStyleProperty = - DependencyProperty.Register("LayoutItemContainerStyle", typeof(Style), typeof(DockingManager), - new FrameworkPropertyMetadata((Style)null, - new PropertyChangedCallback(OnLayoutItemContainerStyleChanged))); - - /// - /// Gets or sets the LayoutItemContainerStyle property. This dependency property - /// indicates the style to apply to LayoutDocumentItem objects. A LayoutDocumentItem object is created when a new LayoutDocument is created inside the current Layout. - /// - public Style LayoutItemContainerStyle + + void AttachLayoutItems() + { + if( Layout != null ) + { + foreach( var document in Layout.Descendents().OfType().ToArray() ) { - get { return (Style)GetValue(LayoutItemContainerStyleProperty); } - set { SetValue(LayoutItemContainerStyleProperty, value); } + CreateDocumentLayoutItem( document ); + //var documentItem = new LayoutDocumentItem(); + //documentItem.Attach(document); + //ApplyStyleToLayoutItem(documentItem); + //_layoutItems.Add(documentItem); } - - /// - /// Handles changes to the LayoutItemContainerStyle property. - /// - private static void OnLayoutItemContainerStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + foreach( var anchorable in Layout.Descendents().OfType().ToArray() ) { - ((DockingManager)d).OnLayoutItemContainerStyleChanged(e); + CreateAnchorableLayoutItem( anchorable ); + //var anchorableItem = new LayoutAnchorableItem(); + //anchorableItem.Attach(anchorable); + //ApplyStyleToLayoutItem(anchorableItem); + //_layoutItems.Add(anchorableItem); } - /// - /// Provides derived classes an opportunity to handle changes to the LayoutItemContainerStyle property. - /// - protected virtual void OnLayoutItemContainerStyleChanged(DependencyPropertyChangedEventArgs e) + Layout.ElementAdded += new EventHandler( Layout_ElementAdded ); + Layout.ElementRemoved += new EventHandler( Layout_ElementRemoved ); + } + } + + void ApplyStyleToLayoutItem( LayoutItem layoutItem ) + { + layoutItem._ClearDefaultBindings(); + if( LayoutItemContainerStyle != null ) + layoutItem.Style = LayoutItemContainerStyle; + else if( LayoutItemContainerStyleSelector != null ) + layoutItem.Style = LayoutItemContainerStyleSelector.SelectStyle( layoutItem.Model, layoutItem ); + layoutItem._SetDefaultBindings(); + } + + void CreateAnchorableLayoutItem( LayoutAnchorable contentToAttach ) + { + if( _layoutItems.Any( item => item.LayoutElement == contentToAttach ) ) + { + foreach( var item in _layoutItems ) { - AttachLayoutItems(); + ApplyStyleToLayoutItem( item ); } + return; + } - #endregion + var layoutItem = new LayoutAnchorableItem(); + layoutItem.Attach( contentToAttach ); + ApplyStyleToLayoutItem( layoutItem ); + _layoutItems.Add( layoutItem ); - #region LayoutItemContainerStyleSelector + if( contentToAttach != null && + contentToAttach.Content != null && + contentToAttach.Content is UIElement ) + { + InternalAddLogicalChild( contentToAttach.Content ); + } - /// - /// LayoutItemContainerStyleSelector Dependency Property - /// - public static readonly DependencyProperty LayoutItemContainerStyleSelectorProperty = - DependencyProperty.Register("LayoutItemContainerStyleSelector", typeof(StyleSelector), typeof(DockingManager), - new FrameworkPropertyMetadata((StyleSelector)null, - new PropertyChangedCallback(OnLayoutItemContainerStyleSelectorChanged))); + } - /// - /// Gets or sets the LayoutItemContainerStyleSelector property. This dependency property - /// indicates style selector of the LayoutDocumentItemStyle. - /// - public StyleSelector LayoutItemContainerStyleSelector + void CreateDocumentLayoutItem( LayoutDocument contentToAttach ) + { + if( _layoutItems.Any( item => item.LayoutElement == contentToAttach ) ) + { + foreach( var item in _layoutItems ) { - get { return (StyleSelector)GetValue(LayoutItemContainerStyleSelectorProperty); } - set { SetValue(LayoutItemContainerStyleSelectorProperty, value); } + ApplyStyleToLayoutItem( item ); } + return; + } - /// - /// Handles changes to the LayoutItemContainerStyleSelector property. - /// - private static void OnLayoutItemContainerStyleSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((DockingManager)d).OnLayoutItemContainerStyleSelectorChanged(e); - } + var layoutItem = new LayoutDocumentItem(); + layoutItem.Attach( contentToAttach ); + ApplyStyleToLayoutItem( layoutItem ); + _layoutItems.Add( layoutItem ); - /// - /// Provides derived classes an opportunity to handle changes to the LayoutItemContainerStyleSelector property. - /// - protected virtual void OnLayoutItemContainerStyleSelectorChanged(DependencyPropertyChangedEventArgs e) - { - AttachLayoutItems(); - } + if( contentToAttach != null && + contentToAttach.Content != null && + contentToAttach.Content is UIElement ) + { + InternalAddLogicalChild( contentToAttach.Content ); + } - #endregion + } - /// - /// Return the LayoutItem wrapper for the content passed as argument - /// - /// LayoutContent to search - /// Either a LayoutAnchorableItem or LayoutDocumentItem which contains the LayoutContent passed as argument - public LayoutItem GetLayoutItemFromModel(LayoutContent content) - { - return _layoutItems.FirstOrDefault(item => item.LayoutElement == content); - } - #endregion + #region LayoutItemContainerStyle + + /// + /// LayoutItemContainerStyle Dependency Property + /// + public static readonly DependencyProperty LayoutItemContainerStyleProperty = + DependencyProperty.Register( "LayoutItemContainerStyle", typeof( Style ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( Style )null, + new PropertyChangedCallback( OnLayoutItemContainerStyleChanged ) ) ); + + /// + /// Gets or sets the LayoutItemContainerStyle property. This dependency property + /// indicates the style to apply to LayoutDocumentItem objects. A LayoutDocumentItem object is created when a new LayoutDocument is created inside the current Layout. + /// + public Style LayoutItemContainerStyle + { + get + { + return ( Style )GetValue( LayoutItemContainerStyleProperty ); + } + set + { + SetValue( LayoutItemContainerStyleProperty, value ); + } + } - #region NavigatorWindow - NavigatorWindow _navigatorWindow = null; + /// + /// Handles changes to the LayoutItemContainerStyle property. + /// + private static void OnLayoutItemContainerStyleChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnLayoutItemContainerStyleChanged( e ); + } - void ShowNavigatorWindow() - { - if (_navigatorWindow == null) - { - _navigatorWindow = new NavigatorWindow(this) - { - Owner = Window.GetWindow(this), - WindowStartupLocation = WindowStartupLocation.CenterOwner - }; - } + /// + /// Provides derived classes an opportunity to handle changes to the LayoutItemContainerStyle property. + /// + protected virtual void OnLayoutItemContainerStyleChanged( DependencyPropertyChangedEventArgs e ) + { + AttachLayoutItems(); + } - _navigatorWindow.ShowDialog(); - _navigatorWindow = null; - } + #endregion - bool IsNavigatorWindowActive - { - get { return _navigatorWindow != null; } - } + #region LayoutItemContainerStyleSelector + /// + /// LayoutItemContainerStyleSelector Dependency Property + /// + public static readonly DependencyProperty LayoutItemContainerStyleSelectorProperty = + DependencyProperty.Register( "LayoutItemContainerStyleSelector", typeof( StyleSelector ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( StyleSelector )null, + new PropertyChangedCallback( OnLayoutItemContainerStyleSelectorChanged ) ) ); - protected override void OnPreviewKeyDown(KeyEventArgs e) - { - if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) - { - if (e.IsDown && e.Key == Key.Tab) - { - if (!IsNavigatorWindowActive) - { - ShowNavigatorWindow(); - e.Handled = true; - } - } - } + /// + /// Gets or sets the LayoutItemContainerStyleSelector property. This dependency property + /// indicates style selector of the LayoutDocumentItemStyle. + /// + public StyleSelector LayoutItemContainerStyleSelector + { + get + { + return ( StyleSelector )GetValue( LayoutItemContainerStyleSelectorProperty ); + } + set + { + SetValue( LayoutItemContainerStyleSelectorProperty, value ); + } + } - base.OnPreviewKeyDown(e); - } + /// + /// Handles changes to the LayoutItemContainerStyleSelector property. + /// + private static void OnLayoutItemContainerStyleSelectorChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) + { + ( ( DockingManager )d ).OnLayoutItemContainerStyleSelectorChanged( e ); + } + + /// + /// Provides derived classes an opportunity to handle changes to the LayoutItemContainerStyleSelector property. + /// + protected virtual void OnLayoutItemContainerStyleSelectorChanged( DependencyPropertyChangedEventArgs e ) + { + AttachLayoutItems(); + } - #endregion + #endregion - #region ShowSystemMenu + /// + /// Return the LayoutItem wrapper for the content passed as argument + /// + /// LayoutContent to search + /// Either a LayoutAnchorableItem or LayoutDocumentItem which contains the LayoutContent passed as argument + public LayoutItem GetLayoutItemFromModel( LayoutContent content ) + { + return _layoutItems.FirstOrDefault( item => item.LayoutElement == content ); + } + #endregion - /// - /// ShowSystemMenu Dependency Property - /// - public static readonly DependencyProperty ShowSystemMenuProperty = - DependencyProperty.Register("ShowSystemMenu", typeof(bool), typeof(DockingManager), - new FrameworkPropertyMetadata((bool)true)); + #region NavigatorWindow + NavigatorWindow _navigatorWindow = null; - /// - /// Gets or sets the ShowSystemMenu property. This dependency property - /// indicates if floating windows should show the system menu when a custom context menu is not defined. - /// - public bool ShowSystemMenu + void ShowNavigatorWindow() + { + if( _navigatorWindow == null ) + { + _navigatorWindow = new NavigatorWindow( this ) { - get { return (bool)GetValue(ShowSystemMenuProperty); } - set { SetValue(ShowSystemMenuProperty, value); } - } + Owner = Window.GetWindow( this ), + WindowStartupLocation = WindowStartupLocation.CenterOwner + }; + } - #endregion + _navigatorWindow.ShowDialog(); + _navigatorWindow = null; + } - #region AllowMixedOrientation + bool IsNavigatorWindowActive + { + get + { + return _navigatorWindow != null; + } + } - /// - /// AllowMixedOrientation Dependency Property - /// - public static readonly DependencyProperty AllowMixedOrientationProperty = - DependencyProperty.Register("AllowMixedOrientation", typeof(bool), typeof(DockingManager), - new FrameworkPropertyMetadata((bool)false)); - /// - /// Gets or sets the AllowMixedOrientation property. This dependency property - /// indicates if the manager should allow mixed orientation for document panes. - /// - public bool AllowMixedOrientation + protected override void OnPreviewKeyDown( KeyEventArgs e ) + { + if( Keyboard.IsKeyDown( Key.LeftCtrl ) || Keyboard.IsKeyDown( Key.RightCtrl ) ) + { + if( e.IsDown && e.Key == Key.Tab ) { - get { return (bool)GetValue(AllowMixedOrientationProperty); } - set { SetValue(AllowMixedOrientationProperty, value); } + if( !IsNavigatorWindowActive ) + { + ShowNavigatorWindow(); + e.Handled = true; + } } + } + + base.OnPreviewKeyDown( e ); + } + + #endregion + + #region ShowSystemMenu + + /// + /// ShowSystemMenu Dependency Property + /// + public static readonly DependencyProperty ShowSystemMenuProperty = + DependencyProperty.Register( "ShowSystemMenu", typeof( bool ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( bool )true ) ); + + /// + /// Gets or sets the ShowSystemMenu property. This dependency property + /// indicates if floating windows should show the system menu when a custom context menu is not defined. + /// + public bool ShowSystemMenu + { + get + { + return ( bool )GetValue( ShowSystemMenuProperty ); + } + set + { + SetValue( ShowSystemMenuProperty, value ); + } + } - #endregion + #endregion + #region AllowMixedOrientation + /// + /// AllowMixedOrientation Dependency Property + /// + public static readonly DependencyProperty AllowMixedOrientationProperty = + DependencyProperty.Register( "AllowMixedOrientation", typeof( bool ), typeof( DockingManager ), + new FrameworkPropertyMetadata( ( bool )false ) ); + + /// + /// Gets or sets the AllowMixedOrientation property. This dependency property + /// indicates if the manager should allow mixed orientation for document panes. + /// + public bool AllowMixedOrientation + { + get + { + return ( bool )GetValue( AllowMixedOrientationProperty ); + } + set + { + SetValue( AllowMixedOrientationProperty, value ); + } } + + #endregion + + + } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorable.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorable.cs index 1b2f5b35..f298300f 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorable.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Layout/LayoutAnchorable.cs @@ -26,622 +26,670 @@ using System.ComponentModel; namespace Xceed.Wpf.AvalonDock.Layout { - [Serializable] - public class LayoutAnchorable : LayoutContent + [Serializable] + public class LayoutAnchorable : LayoutContent + { + public LayoutAnchorable() { - #region IsVisible - [XmlIgnore] - public bool IsVisible - { - get - { - return Parent != null && !(Parent is LayoutRoot); - } - set - { - if (value) - { - Show(); - } - else - { - Hide(); - } - } - } - - public event EventHandler IsVisibleChanged; + // LayoutAnchorable will hide by default, not close. + _canClose = false; + } - void NotifyIsVisibleChanged() + #region IsVisible + [XmlIgnore] + public bool IsVisible + { + get + { + return Parent != null && !( Parent is LayoutRoot ); + } + set + { + if( value ) { - if (IsVisibleChanged != null) - IsVisibleChanged(this, EventArgs.Empty); + Show(); } - - [XmlIgnore] - public bool IsHidden + else { - get - { - return (Parent is LayoutRoot); - } + Hide(); } + } + } - protected override void OnParentChanged(ILayoutContainer oldValue, ILayoutContainer newValue) - { - UpdateParentVisibility(); - RaisePropertyChanged("IsVisible"); - NotifyIsVisibleChanged(); - RaisePropertyChanged("IsHidden"); - RaisePropertyChanged("IsAutoHidden"); - base.OnParentChanged(oldValue, newValue); - } + public event EventHandler IsVisibleChanged; - void UpdateParentVisibility() - { - var parentPane = Parent as ILayoutElementWithVisibility; - if (parentPane != null) - parentPane.ComputeVisibility(); - } + void NotifyIsVisibleChanged() + { + if( IsVisibleChanged != null ) + IsVisibleChanged( this, EventArgs.Empty ); + } - #endregion + [XmlIgnore] + public bool IsHidden + { + get + { + return ( Parent is LayoutRoot ); + } + } + + protected override void OnParentChanged( ILayoutContainer oldValue, ILayoutContainer newValue ) + { + UpdateParentVisibility(); + RaisePropertyChanged( "IsVisible" ); + NotifyIsVisibleChanged(); + RaisePropertyChanged( "IsHidden" ); + RaisePropertyChanged( "IsAutoHidden" ); + base.OnParentChanged( oldValue, newValue ); + } + + void UpdateParentVisibility() + { + var parentPane = Parent as ILayoutElementWithVisibility; + if( parentPane != null ) + parentPane.ComputeVisibility(); + } + + #endregion - #region AutoHideWidth + #region AutoHideWidth - private double _autohideWidth = 0.0; - public double AutoHideWidth + private double _autohideWidth = 0.0; + public double AutoHideWidth + { + get + { + return _autohideWidth; + } + set + { + if( _autohideWidth != value ) { - get { return _autohideWidth; } - set - { - if (_autohideWidth != value) - { - RaisePropertyChanging("AutoHideWidth"); - value = Math.Max(value, _autohideMinWidth); - _autohideWidth = value; - RaisePropertyChanged("AutoHideWidth"); - } - } + RaisePropertyChanging( "AutoHideWidth" ); + value = Math.Max( value, _autohideMinWidth ); + _autohideWidth = value; + RaisePropertyChanged( "AutoHideWidth" ); } + } + } - #endregion + #endregion - #region AutoHideMinWidth + #region AutoHideMinWidth - private double _autohideMinWidth = 100.0; - public double AutoHideMinWidth + private double _autohideMinWidth = 100.0; + public double AutoHideMinWidth + { + get + { + return _autohideMinWidth; + } + set + { + if( _autohideMinWidth != value ) { - get { return _autohideMinWidth; } - set - { - if (_autohideMinWidth != value) - { - RaisePropertyChanging("AutoHideMinWidth"); - if (value < 0) - throw new ArgumentException("value"); - _autohideMinWidth = value; - RaisePropertyChanged("AutoHideMinWidth"); - } - } + RaisePropertyChanging( "AutoHideMinWidth" ); + if( value < 0 ) + throw new ArgumentException( "value" ); + _autohideMinWidth = value; + RaisePropertyChanged( "AutoHideMinWidth" ); } + } + } - #endregion + #endregion - #region AutoHideHeight + #region AutoHideHeight - private double _autohideHeight = 0.0; - public double AutoHideHeight + private double _autohideHeight = 0.0; + public double AutoHideHeight + { + get + { + return _autohideHeight; + } + set + { + if( _autohideHeight != value ) { - get { return _autohideHeight; } - set - { - if (_autohideHeight != value) - { - RaisePropertyChanging("AutoHideHeight"); - value = Math.Max(value, _autohideMinHeight); - _autohideHeight = value; - RaisePropertyChanged("AutoHideHeight"); - } - } + RaisePropertyChanging( "AutoHideHeight" ); + value = Math.Max( value, _autohideMinHeight ); + _autohideHeight = value; + RaisePropertyChanged( "AutoHideHeight" ); } + } + } - #endregion + #endregion - #region AutoHideMinHeight + #region AutoHideMinHeight - private double _autohideMinHeight = 100.0; - public double AutoHideMinHeight + private double _autohideMinHeight = 100.0; + public double AutoHideMinHeight + { + get + { + return _autohideMinHeight; + } + set + { + if( _autohideMinHeight != value ) { - get { return _autohideMinHeight; } - set - { - if (_autohideMinHeight != value) - { - RaisePropertyChanging("AutoHideMinHeight"); - if (value < 0) - throw new ArgumentException("value"); - _autohideMinHeight = value; - RaisePropertyChanged("AutoHideMinHeight"); - } - } + RaisePropertyChanging( "AutoHideMinHeight" ); + if( value < 0 ) + throw new ArgumentException( "value" ); + _autohideMinHeight = value; + RaisePropertyChanged( "AutoHideMinHeight" ); } + } + } - #endregion + #endregion - /// - /// Hide this contents - /// - /// Add this content to collection of parent root. - public void Hide(bool cancelable = true) - { - if (!IsVisible) - { - IsSelected = true; - IsActive = true; - return; - } + /// + /// Hide this contents + /// + /// Add this content to collection of parent root. + public void Hide( bool cancelable = true ) + { + if( !IsVisible ) + { + IsSelected = true; + IsActive = true; + return; + } + + if( cancelable ) + { + CancelEventArgs args = new CancelEventArgs(); + OnHiding( args ); + if( args.Cancel ) + return; + } + + RaisePropertyChanging( "IsHidden" ); + RaisePropertyChanging( "IsVisible" ); + //if (Parent is ILayoutPane) + { + var parentAsGroup = Parent as ILayoutGroup; + PreviousContainer = parentAsGroup; + PreviousContainerIndex = parentAsGroup.IndexOfChild( this ); + } + Root.Hidden.Add( this ); + RaisePropertyChanged( "IsVisible" ); + RaisePropertyChanged( "IsHidden" ); + NotifyIsVisibleChanged(); + } - if (cancelable) - { - CancelEventArgs args = new CancelEventArgs(); - OnHiding(args); - if (args.Cancel) - return; - } + public event EventHandler Hiding; - RaisePropertyChanging("IsHidden"); - RaisePropertyChanging("IsVisible"); - //if (Parent is ILayoutPane) - { - var parentAsGroup = Parent as ILayoutGroup; - PreviousContainer = parentAsGroup; - PreviousContainerIndex = parentAsGroup.IndexOfChild(this); - } - Root.Hidden.Add(this); - RaisePropertyChanged("IsVisible"); - RaisePropertyChanged("IsHidden"); - NotifyIsVisibleChanged(); - } + protected virtual void OnHiding( CancelEventArgs args ) + { + if( Hiding != null ) + Hiding( this, args ); + } - public event EventHandler Hiding; - protected virtual void OnHiding(CancelEventArgs args) + /// + /// Show the content + /// + /// Try to show the content where it was previously hidden. + public void Show() + { + if( IsVisible ) + return; + + if( !IsHidden ) + throw new InvalidOperationException(); + + RaisePropertyChanging( "IsHidden" ); + RaisePropertyChanging( "IsVisible" ); + + bool added = false; + var root = Root; + if( root != null && root.Manager != null ) + { + if( root.Manager.LayoutUpdateStrategy != null ) + added = root.Manager.LayoutUpdateStrategy.BeforeInsertAnchorable( root as LayoutRoot, this, PreviousContainer ); + } + + if( !added && PreviousContainer != null ) + { + var previousContainerAsLayoutGroup = PreviousContainer as ILayoutGroup; + if( PreviousContainerIndex < previousContainerAsLayoutGroup.ChildrenCount ) + previousContainerAsLayoutGroup.InsertChildAt( PreviousContainerIndex, this ); + else + previousContainerAsLayoutGroup.InsertChildAt( previousContainerAsLayoutGroup.ChildrenCount, this ); + IsSelected = true; + IsActive = true; + } + + if( root != null && root.Manager != null ) + { + if( root.Manager.LayoutUpdateStrategy != null ) { - if (Hiding != null) - Hiding(this, args); + root.Manager.LayoutUpdateStrategy.AfterInsertAnchorable( root as LayoutRoot, this ); } + } + PreviousContainer = null; + PreviousContainerIndex = -1; - /// - /// Show the content - /// - /// Try to show the content where it was previously hidden. - public void Show() + RaisePropertyChanged( "IsVisible" ); + RaisePropertyChanged( "IsHidden" ); + NotifyIsVisibleChanged(); + } + + protected override void InternalDock() + { + var root = Root as LayoutRoot; + LayoutAnchorablePane anchorablePane = null; + + if( root.ActiveContent != null && + root.ActiveContent != this ) + { + //look for active content parent pane + anchorablePane = root.ActiveContent.Parent as LayoutAnchorablePane; + } + + if( anchorablePane == null ) + { + //look for a pane on the right side + anchorablePane = root.Descendents().OfType().Where( pane => !pane.IsHostedInFloatingWindow && pane.GetSide() == AnchorSide.Right ).FirstOrDefault(); + } + + if( anchorablePane == null ) + { + //look for an available pane + anchorablePane = root.Descendents().OfType().FirstOrDefault(); + } + + + bool added = false; + if( root.Manager.LayoutUpdateStrategy != null ) + { + added = root.Manager.LayoutUpdateStrategy.BeforeInsertAnchorable( root, this, anchorablePane ); + } + + if( !added ) + { + if( anchorablePane == null ) { - if (IsVisible) - return; + var mainLayoutPanel = new LayoutPanel() { Orientation = Orientation.Horizontal }; + if( root.RootPanel != null ) + { + mainLayoutPanel.Children.Add( root.RootPanel ); + } - if (!IsHidden) - throw new InvalidOperationException(); + root.RootPanel = mainLayoutPanel; + anchorablePane = new LayoutAnchorablePane() { DockWidth = new GridLength( 200.0, GridUnitType.Pixel ) }; + mainLayoutPanel.Children.Add( anchorablePane ); + } - RaisePropertyChanging("IsHidden"); - RaisePropertyChanging("IsVisible"); + anchorablePane.Children.Add( this ); + added = true; + } - bool added = false; - var root = Root; - if (root != null && root.Manager != null) - { - if (root.Manager.LayoutUpdateStrategy != null) - added = root.Manager.LayoutUpdateStrategy.BeforeInsertAnchorable(root as LayoutRoot, this, PreviousContainer); - } + if( root.Manager.LayoutUpdateStrategy != null ) + { + root.Manager.LayoutUpdateStrategy.AfterInsertAnchorable( root, this ); + } - if (!added && PreviousContainer != null) - { - var previousContainerAsLayoutGroup = PreviousContainer as ILayoutGroup; - if (PreviousContainerIndex < previousContainerAsLayoutGroup.ChildrenCount) - previousContainerAsLayoutGroup.InsertChildAt(PreviousContainerIndex, this); - else - previousContainerAsLayoutGroup.InsertChildAt(previousContainerAsLayoutGroup.ChildrenCount, this); - IsSelected = true; - IsActive = true; - } + base.InternalDock(); + } - if (root != null && root.Manager != null) - { - if (root.Manager.LayoutUpdateStrategy != null) - { - root.Manager.LayoutUpdateStrategy.AfterInsertAnchorable(root as LayoutRoot, this); - } - } + /// + /// Add the anchorable to a DockingManager layout + /// + /// + /// + public void AddToLayout( DockingManager manager, AnchorableShowStrategy strategy ) + { + if( IsVisible || + IsHidden ) + throw new InvalidOperationException(); + + + bool most = ( strategy & AnchorableShowStrategy.Most ) == AnchorableShowStrategy.Most; + bool left = ( strategy & AnchorableShowStrategy.Left ) == AnchorableShowStrategy.Left; + bool right = ( strategy & AnchorableShowStrategy.Right ) == AnchorableShowStrategy.Right; + bool top = ( strategy & AnchorableShowStrategy.Top ) == AnchorableShowStrategy.Top; + bool bottom = ( strategy & AnchorableShowStrategy.Bottom ) == AnchorableShowStrategy.Bottom; + + if( !most ) + { + var side = AnchorSide.Left; + if( left ) + side = AnchorSide.Left; + if( right ) + side = AnchorSide.Right; + if( top ) + side = AnchorSide.Top; + if( bottom ) + side = AnchorSide.Bottom; + + var anchorablePane = manager.Layout.Descendents().OfType().FirstOrDefault( p => p.GetSide() == side ); + if( anchorablePane != null ) + anchorablePane.Children.Add( this ); + else + most = true; + } + + + if( most ) + { + if( manager.Layout.RootPanel == null ) + manager.Layout.RootPanel = new LayoutPanel() { Orientation = ( left || right ? Orientation.Horizontal : Orientation.Vertical ) }; + + if( left || right ) + { + if( manager.Layout.RootPanel.Orientation == Orientation.Vertical && + manager.Layout.RootPanel.ChildrenCount > 1 ) + { + manager.Layout.RootPanel = new LayoutPanel( manager.Layout.RootPanel ); + } - PreviousContainer = null; - PreviousContainerIndex = -1; + manager.Layout.RootPanel.Orientation = Orientation.Horizontal; - RaisePropertyChanged("IsVisible"); - RaisePropertyChanged("IsHidden"); - NotifyIsVisibleChanged(); + if( left ) + manager.Layout.RootPanel.Children.Insert( 0, new LayoutAnchorablePane( this ) ); + else + manager.Layout.RootPanel.Children.Add( new LayoutAnchorablePane( this ) ); } - - protected override void InternalDock() + else { - var root = Root as LayoutRoot; - LayoutAnchorablePane anchorablePane = null; - - if (root.ActiveContent != null && - root.ActiveContent != this) - { - //look for active content parent pane - anchorablePane = root.ActiveContent.Parent as LayoutAnchorablePane; - } + if( manager.Layout.RootPanel.Orientation == Orientation.Horizontal && + manager.Layout.RootPanel.ChildrenCount > 1 ) + { + manager.Layout.RootPanel = new LayoutPanel( manager.Layout.RootPanel ); + } - if (anchorablePane == null) - { - //look for a pane on the right side - anchorablePane = root.Descendents().OfType().Where(pane => !pane.IsHostedInFloatingWindow && pane.GetSide() == AnchorSide.Right).FirstOrDefault(); - } + manager.Layout.RootPanel.Orientation = Orientation.Vertical; - if (anchorablePane == null) - { - //look for an available pane - anchorablePane = root.Descendents().OfType().FirstOrDefault(); - } + if( top ) + manager.Layout.RootPanel.Children.Insert( 0, new LayoutAnchorablePane( this ) ); + else + manager.Layout.RootPanel.Children.Add( new LayoutAnchorablePane( this ) ); + } + } + } - bool added = false; - if (root.Manager.LayoutUpdateStrategy != null) - { - added = root.Manager.LayoutUpdateStrategy.BeforeInsertAnchorable(root, this, anchorablePane); - } - if (!added) - { - if (anchorablePane == null) - { - var mainLayoutPanel = new LayoutPanel() { Orientation = Orientation.Horizontal }; - if (root.RootPanel != null) - { - mainLayoutPanel.Children.Add(root.RootPanel); - } - - root.RootPanel = mainLayoutPanel; - anchorablePane = new LayoutAnchorablePane() { DockWidth = new GridLength(200.0, GridUnitType.Pixel) }; - mainLayoutPanel.Children.Add(anchorablePane); - } - - anchorablePane.Children.Add(this); - added = true; - } + /// + /// Get a value indicating if the anchorable is anchored to a border in an autohide status + /// + public bool IsAutoHidden + { + get + { + return Parent != null && Parent is LayoutAnchorGroup; + } + } - if (root.Manager.LayoutUpdateStrategy != null) - { - root.Manager.LayoutUpdateStrategy.AfterInsertAnchorable(root, this); - } - base.InternalDock(); + #region AutoHide + public void ToggleAutoHide() + { + #region Anchorable is already auto hidden + if( IsAutoHidden ) + { + var parentGroup = Parent as LayoutAnchorGroup; + var parentSide = parentGroup.Parent as LayoutAnchorSide; + var previousContainer = ( ( ILayoutPreviousContainer )parentGroup ).PreviousContainer as LayoutAnchorablePane; + + if( previousContainer == null ) + { + AnchorSide side = ( parentGroup.Parent as LayoutAnchorSide ).Side; + switch( side ) + { + case AnchorSide.Right: + if( parentGroup.Root.RootPanel.Orientation == Orientation.Horizontal ) + { + previousContainer = new LayoutAnchorablePane(); + previousContainer.DockMinWidth = this.AutoHideMinWidth; + parentGroup.Root.RootPanel.Children.Add( previousContainer ); + } + else + { + previousContainer = new LayoutAnchorablePane(); + LayoutPanel panel = new LayoutPanel() { Orientation = Orientation.Horizontal }; + LayoutRoot root = parentGroup.Root as LayoutRoot; + LayoutPanel oldRootPanel = parentGroup.Root.RootPanel as LayoutPanel; + root.RootPanel = panel; + panel.Children.Add( oldRootPanel ); + panel.Children.Add( previousContainer ); + } + break; + case AnchorSide.Left: + if( parentGroup.Root.RootPanel.Orientation == Orientation.Horizontal ) + { + previousContainer = new LayoutAnchorablePane(); + previousContainer.DockMinWidth = this.AutoHideMinWidth; + parentGroup.Root.RootPanel.Children.Insert( 0, previousContainer ); + } + else + { + previousContainer = new LayoutAnchorablePane(); + LayoutPanel panel = new LayoutPanel() { Orientation = Orientation.Horizontal }; + LayoutRoot root = parentGroup.Root as LayoutRoot; + LayoutPanel oldRootPanel = parentGroup.Root.RootPanel as LayoutPanel; + root.RootPanel = panel; + panel.Children.Add( previousContainer ); + panel.Children.Add( oldRootPanel ); + } + break; + case AnchorSide.Top: + if( parentGroup.Root.RootPanel.Orientation == Orientation.Vertical ) + { + previousContainer = new LayoutAnchorablePane(); + previousContainer.DockMinHeight = this.AutoHideMinHeight; + parentGroup.Root.RootPanel.Children.Insert( 0, previousContainer ); + } + else + { + previousContainer = new LayoutAnchorablePane(); + LayoutPanel panel = new LayoutPanel() { Orientation = Orientation.Vertical }; + LayoutRoot root = parentGroup.Root as LayoutRoot; + LayoutPanel oldRootPanel = parentGroup.Root.RootPanel as LayoutPanel; + root.RootPanel = panel; + panel.Children.Add( previousContainer ); + panel.Children.Add( oldRootPanel ); + } + break; + case AnchorSide.Bottom: + if( parentGroup.Root.RootPanel.Orientation == Orientation.Vertical ) + { + previousContainer = new LayoutAnchorablePane(); + previousContainer.DockMinHeight = this.AutoHideMinHeight; + parentGroup.Root.RootPanel.Children.Add( previousContainer ); + } + else + { + previousContainer = new LayoutAnchorablePane(); + LayoutPanel panel = new LayoutPanel() { Orientation = Orientation.Vertical }; + LayoutRoot root = parentGroup.Root as LayoutRoot; + LayoutPanel oldRootPanel = parentGroup.Root.RootPanel as LayoutPanel; + root.RootPanel = panel; + panel.Children.Add( oldRootPanel ); + panel.Children.Add( previousContainer ); + } + break; + } } - - /// - /// Add the anchorable to a DockingManager layout - /// - /// - /// - public void AddToLayout(DockingManager manager, AnchorableShowStrategy strategy) + else { - if (IsVisible || - IsHidden) - throw new InvalidOperationException(); - - - bool most = (strategy & AnchorableShowStrategy.Most) == AnchorableShowStrategy.Most; - bool left = (strategy & AnchorableShowStrategy.Left) == AnchorableShowStrategy.Left; - bool right = (strategy & AnchorableShowStrategy.Right) == AnchorableShowStrategy.Right; - bool top = (strategy & AnchorableShowStrategy.Top) == AnchorableShowStrategy.Top; - bool bottom = (strategy & AnchorableShowStrategy.Bottom) == AnchorableShowStrategy.Bottom; - - if (!most) - { - var side = AnchorSide.Left; - if (left) - side = AnchorSide.Left; - if (right) - side = AnchorSide.Right; - if (top) - side = AnchorSide.Top; - if (bottom) - side = AnchorSide.Bottom; - - var anchorablePane = manager.Layout.Descendents().OfType().FirstOrDefault(p => p.GetSide() == side); - if (anchorablePane != null) - anchorablePane.Children.Add(this); - else - most = true; - } - - - if (most) - { - if (manager.Layout.RootPanel == null) - manager.Layout.RootPanel = new LayoutPanel() { Orientation = (left || right ? Orientation.Horizontal : Orientation.Vertical) }; - - if (left || right) - { - if (manager.Layout.RootPanel.Orientation == Orientation.Vertical && - manager.Layout.RootPanel.ChildrenCount > 1) - { - manager.Layout.RootPanel = new LayoutPanel(manager.Layout.RootPanel); - } - - manager.Layout.RootPanel.Orientation = Orientation.Horizontal; - - if (left) - manager.Layout.RootPanel.Children.Insert(0, new LayoutAnchorablePane(this)); - else - manager.Layout.RootPanel.Children.Add(new LayoutAnchorablePane(this)); - } - else - { - if (manager.Layout.RootPanel.Orientation == Orientation.Horizontal && - manager.Layout.RootPanel.ChildrenCount > 1) - { - manager.Layout.RootPanel = new LayoutPanel(manager.Layout.RootPanel); - } - - manager.Layout.RootPanel.Orientation = Orientation.Vertical; - - if (top) - manager.Layout.RootPanel.Children.Insert(0, new LayoutAnchorablePane(this)); - else - manager.Layout.RootPanel.Children.Add(new LayoutAnchorablePane(this)); - } + //I'm about to remove parentGroup, redirect any content (ie hidden contents) that point to it + //to previousContainer + LayoutRoot root = parentGroup.Root as LayoutRoot; + foreach( var cnt in root.Descendents().OfType().Where( c => c.PreviousContainer == parentGroup ) ) + { + cnt.PreviousContainer = previousContainer; + } + } - } + foreach( var anchorableToToggle in parentGroup.Children.ToArray() ) + { + previousContainer.Children.Add( anchorableToToggle ); } + parentSide.Children.Remove( parentGroup ); - /// - /// Get a value indicating if the anchorable is anchored to a border in an autohide status - /// - public bool IsAutoHidden + var parent = previousContainer.Parent as LayoutGroupBase; + while( ( parent != null ) ) { - get { return Parent != null && Parent is LayoutAnchorGroup; } + if( parent is LayoutGroup ) + { + (( LayoutGroup )parent).ComputeVisibility(); + } + parent = parent.Parent as LayoutGroupBase; } + } + #endregion + #region Anchorable is docked + else if( Parent is LayoutAnchorablePane ) + { + var root = Root; + var parentPane = Parent as LayoutAnchorablePane; + + var newAnchorGroup = new LayoutAnchorGroup(); + + ( ( ILayoutPreviousContainer )newAnchorGroup ).PreviousContainer = parentPane; + foreach( var anchorableToImport in parentPane.Children.ToArray() ) + newAnchorGroup.Children.Add( anchorableToImport ); - #region AutoHide - public void ToggleAutoHide() + //detect anchor side for the pane + var anchorSide = parentPane.GetSide(); + + switch( anchorSide ) { - #region Anchorable is already auto hidden - if (IsAutoHidden) + case AnchorSide.Right: + if( root.RightSide != null ) { - var parentGroup = Parent as LayoutAnchorGroup; - var parentSide = parentGroup.Parent as LayoutAnchorSide; - var previousContainer = ((ILayoutPreviousContainer)parentGroup).PreviousContainer as LayoutAnchorablePane; - - if (previousContainer == null) - { - AnchorSide side = (parentGroup.Parent as LayoutAnchorSide).Side; - switch (side) - { - case AnchorSide.Right: - if (parentGroup.Root.RootPanel.Orientation == Orientation.Horizontal) - { - previousContainer = new LayoutAnchorablePane(); - previousContainer.DockMinWidth = this.AutoHideMinWidth; - parentGroup.Root.RootPanel.Children.Add(previousContainer); - } - else - { - previousContainer = new LayoutAnchorablePane(); - LayoutPanel panel = new LayoutPanel() { Orientation = Orientation.Horizontal }; - LayoutRoot root = parentGroup.Root as LayoutRoot; - LayoutPanel oldRootPanel = parentGroup.Root.RootPanel as LayoutPanel; - root.RootPanel = panel; - panel.Children.Add(oldRootPanel); - panel.Children.Add(previousContainer); - } - break; - case AnchorSide.Left: - if (parentGroup.Root.RootPanel.Orientation == Orientation.Horizontal) - { - previousContainer = new LayoutAnchorablePane(); - previousContainer.DockMinWidth = this.AutoHideMinWidth; - parentGroup.Root.RootPanel.Children.Insert(0, previousContainer); - } - else - { - previousContainer = new LayoutAnchorablePane(); - LayoutPanel panel = new LayoutPanel() { Orientation = Orientation.Horizontal }; - LayoutRoot root = parentGroup.Root as LayoutRoot; - LayoutPanel oldRootPanel = parentGroup.Root.RootPanel as LayoutPanel; - root.RootPanel = panel; - panel.Children.Add(previousContainer); - panel.Children.Add(oldRootPanel); - } - break; - case AnchorSide.Top: - if (parentGroup.Root.RootPanel.Orientation == Orientation.Vertical) - { - previousContainer = new LayoutAnchorablePane(); - previousContainer.DockMinHeight = this.AutoHideMinHeight; - parentGroup.Root.RootPanel.Children.Insert(0, previousContainer); - } - else - { - previousContainer = new LayoutAnchorablePane(); - LayoutPanel panel = new LayoutPanel() { Orientation = Orientation.Vertical }; - LayoutRoot root = parentGroup.Root as LayoutRoot; - LayoutPanel oldRootPanel = parentGroup.Root.RootPanel as LayoutPanel; - root.RootPanel = panel; - panel.Children.Add(previousContainer); - panel.Children.Add(oldRootPanel); - } - break; - case AnchorSide.Bottom: - if (parentGroup.Root.RootPanel.Orientation == Orientation.Vertical) - { - previousContainer = new LayoutAnchorablePane(); - previousContainer.DockMinHeight = this.AutoHideMinHeight; - parentGroup.Root.RootPanel.Children.Add(previousContainer); - } - else - { - previousContainer = new LayoutAnchorablePane(); - LayoutPanel panel = new LayoutPanel() { Orientation = Orientation.Vertical }; - LayoutRoot root = parentGroup.Root as LayoutRoot; - LayoutPanel oldRootPanel = parentGroup.Root.RootPanel as LayoutPanel; - root.RootPanel = panel; - panel.Children.Add(oldRootPanel); - panel.Children.Add(previousContainer); - } - break; - } - } - else - { - //I'm about to remove parentGroup, redirect any content (ie hidden contents) that point to it - //to previousContainer - LayoutRoot root = parentGroup.Root as LayoutRoot; - foreach (var cnt in root.Descendents().OfType().Where(c => c.PreviousContainer == parentGroup)) - { - cnt.PreviousContainer = previousContainer; - } - } - - - foreach (var anchorableToToggle in parentGroup.Children.ToArray()) - { - previousContainer.Children.Add(anchorableToToggle); - } - - parentSide.Children.Remove(parentGroup); + root.RightSide.Children.Add( newAnchorGroup ); } - #endregion - #region Anchorable is docked - else if (Parent is LayoutAnchorablePane) + break; + case AnchorSide.Left: + if( root.LeftSide != null ) { - var root = Root; - var parentPane = Parent as LayoutAnchorablePane; - - var newAnchorGroup = new LayoutAnchorGroup(); - - ((ILayoutPreviousContainer)newAnchorGroup).PreviousContainer = parentPane; - - foreach (var anchorableToImport in parentPane.Children.ToArray()) - newAnchorGroup.Children.Add(anchorableToImport); - - //detect anchor side for the pane - var anchorSide = parentPane.GetSide(); - - switch (anchorSide) - { - case AnchorSide.Right: - root.RightSide.Children.Add(newAnchorGroup); - break; - case AnchorSide.Left: - root.LeftSide.Children.Add(newAnchorGroup); - break; - case AnchorSide.Top: - root.TopSide.Children.Add(newAnchorGroup); - break; - case AnchorSide.Bottom: - root.BottomSide.Children.Add(newAnchorGroup); - break; - } + root.LeftSide.Children.Add( newAnchorGroup ); } - #endregion + break; + case AnchorSide.Top: + if( root.TopSide != null ) + { + root.TopSide.Children.Add( newAnchorGroup ); + } + break; + case AnchorSide.Bottom: + if( root.BottomSide != null ) + { + root.BottomSide.Children.Add( newAnchorGroup ); + } + break; } + } + #endregion + } - #endregion + #endregion - #region CanHide + #region CanHide - private bool _canHide = true; - public bool CanHide + private bool _canHide = true; + public bool CanHide + { + get + { + return _canHide; + } + set + { + if( _canHide != value ) { - get { return _canHide; } - set - { - if (_canHide != value) - { - _canHide = value; - RaisePropertyChanged("CanHide"); - } - } + _canHide = value; + RaisePropertyChanged( "CanHide" ); } + } + } - #endregion + #endregion - #region CanAutoHide + #region CanAutoHide - private bool _canAutoHide = true; - public bool CanAutoHide + private bool _canAutoHide = true; + public bool CanAutoHide + { + get + { + return _canAutoHide; + } + set + { + if( _canAutoHide != value ) { - get { return _canAutoHide; } - set - { - if (_canAutoHide != value) - { - _canAutoHide = value; - RaisePropertyChanged("CanAutoHide"); - } - } + _canAutoHide = value; + RaisePropertyChanged( "CanAutoHide" ); } + } + } - #endregion + #endregion - public override void ReadXml(System.Xml.XmlReader reader) - { - if (reader.MoveToAttribute("CanHide")) - CanHide = bool.Parse(reader.Value); - if (reader.MoveToAttribute("CanAutoHide")) - CanAutoHide = bool.Parse(reader.Value); - if (reader.MoveToAttribute("AutoHideWidth")) - AutoHideWidth = double.Parse(reader.Value, CultureInfo.InvariantCulture); - if (reader.MoveToAttribute("AutoHideHeight")) - AutoHideHeight = double.Parse(reader.Value, CultureInfo.InvariantCulture); - if (reader.MoveToAttribute("AutoHideMinWidth")) - AutoHideMinWidth = double.Parse(reader.Value, CultureInfo.InvariantCulture); - if (reader.MoveToAttribute("AutoHideMinHeight")) - AutoHideMinHeight = double.Parse(reader.Value, CultureInfo.InvariantCulture); - - base.ReadXml(reader); - } + public override void ReadXml( System.Xml.XmlReader reader ) + { + if( reader.MoveToAttribute( "CanHide" ) ) + CanHide = bool.Parse( reader.Value ); + if( reader.MoveToAttribute( "CanAutoHide" ) ) + CanAutoHide = bool.Parse( reader.Value ); + if( reader.MoveToAttribute( "AutoHideWidth" ) ) + AutoHideWidth = double.Parse( reader.Value, CultureInfo.InvariantCulture ); + if( reader.MoveToAttribute( "AutoHideHeight" ) ) + AutoHideHeight = double.Parse( reader.Value, CultureInfo.InvariantCulture ); + if( reader.MoveToAttribute( "AutoHideMinWidth" ) ) + AutoHideMinWidth = double.Parse( reader.Value, CultureInfo.InvariantCulture ); + if( reader.MoveToAttribute( "AutoHideMinHeight" ) ) + AutoHideMinHeight = double.Parse( reader.Value, CultureInfo.InvariantCulture ); + + base.ReadXml( reader ); + } - public override void WriteXml(System.Xml.XmlWriter writer) - { - if (!CanHide) - writer.WriteAttributeString("CanHide", CanHide.ToString()); - if (!CanAutoHide) - writer.WriteAttributeString("CanAutoHide", CanAutoHide.ToString(CultureInfo.InvariantCulture)); - if (AutoHideWidth > 0) - writer.WriteAttributeString("AutoHideWidth", AutoHideWidth.ToString(CultureInfo.InvariantCulture)); - if (AutoHideHeight > 0) - writer.WriteAttributeString("AutoHideHeight", AutoHideHeight.ToString(CultureInfo.InvariantCulture)); - if (AutoHideMinWidth != 25.0) - writer.WriteAttributeString("AutoHideMinWidth", AutoHideMinWidth.ToString(CultureInfo.InvariantCulture)); - if (AutoHideMinHeight != 25.0) - writer.WriteAttributeString("AutoHideMinHeight", AutoHideMinHeight.ToString(CultureInfo.InvariantCulture)); - - - base.WriteXml(writer); - } + public override void WriteXml( System.Xml.XmlWriter writer ) + { + if( !CanHide ) + writer.WriteAttributeString( "CanHide", CanHide.ToString() ); + if( !CanAutoHide ) + writer.WriteAttributeString( "CanAutoHide", CanAutoHide.ToString( CultureInfo.InvariantCulture ) ); + if( AutoHideWidth > 0 ) + writer.WriteAttributeString( "AutoHideWidth", AutoHideWidth.ToString( CultureInfo.InvariantCulture ) ); + if( AutoHideHeight > 0 ) + writer.WriteAttributeString( "AutoHideHeight", AutoHideHeight.ToString( CultureInfo.InvariantCulture ) ); + if( AutoHideMinWidth != 25.0 ) + writer.WriteAttributeString( "AutoHideMinWidth", AutoHideMinWidth.ToString( CultureInfo.InvariantCulture ) ); + if( AutoHideMinHeight != 25.0 ) + writer.WriteAttributeString( "AutoHideMinHeight", AutoHideMinHeight.ToString( CultureInfo.InvariantCulture ) ); + + + base.WriteXml( writer ); + } - public override void Close() - { - this.CloseAnchorable(); - } + public override void Close() + { + this.CloseAnchorable(); + } - internal void CloseAnchorable() - { - if( this.TestCanClose() ) - { - if( this.IsAutoHidden ) - this.ToggleAutoHide(); + internal void CloseAnchorable() + { + if( this.TestCanClose() ) + { + if( this.IsAutoHidden ) + this.ToggleAutoHide(); - this.CloseInternal(); - } - } + this.CloseInternal(); + } + } #if TRACE @@ -651,5 +699,5 @@ namespace Xceed.Wpf.AvalonDock.Layout System.Diagnostics.Trace.WriteLine( "Anchorable()" ); } #endif - } + } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Layout/LayoutContent.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Layout/LayoutContent.cs index 5be6de32..ec2ef161 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Layout/LayoutContent.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Layout/LayoutContent.cs @@ -744,7 +744,7 @@ namespace Xceed.Wpf.AvalonDock.Layout #region CanClose - private bool _canClose = true; + internal bool _canClose = true; public bool CanClose { get { return _canClose; } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Layout/LayoutRoot.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Layout/LayoutRoot.cs index d55bf630..1170e3bc 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Layout/LayoutRoot.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Layout/LayoutRoot.cs @@ -28,923 +28,966 @@ using System.Xml.Schema; namespace Xceed.Wpf.AvalonDock.Layout { - [ContentProperty("RootPanel")] - [Serializable] - public class LayoutRoot : LayoutElement, ILayoutContainer, ILayoutRoot, IXmlSerializable + [ContentProperty( "RootPanel" )] + [Serializable] + public class LayoutRoot : LayoutElement, ILayoutContainer, ILayoutRoot, IXmlSerializable + { + public LayoutRoot() { - public LayoutRoot() - { - RightSide = new LayoutAnchorSide(); - LeftSide = new LayoutAnchorSide(); - TopSide = new LayoutAnchorSide(); - BottomSide = new LayoutAnchorSide(); - RootPanel = new LayoutPanel(new LayoutDocumentPane()); - } + RightSide = new LayoutAnchorSide(); + LeftSide = new LayoutAnchorSide(); + TopSide = new LayoutAnchorSide(); + BottomSide = new LayoutAnchorSide(); + RootPanel = new LayoutPanel( new LayoutDocumentPane() ); + } - #region RootPanel + #region RootPanel - private LayoutPanel _rootPanel; - public LayoutPanel RootPanel + private LayoutPanel _rootPanel; + public LayoutPanel RootPanel + { + get + { + return _rootPanel; + } + set + { + if( _rootPanel != value ) { - get { return _rootPanel; } - set - { - if (_rootPanel != value) - { - RaisePropertyChanging("RootPanel"); - if (_rootPanel != null && - _rootPanel.Parent == this) - _rootPanel.Parent = null; - _rootPanel = value; - - if (_rootPanel == null) - _rootPanel = new LayoutPanel(new LayoutDocumentPane()); - - if (_rootPanel != null) - _rootPanel.Parent = this; - RaisePropertyChanged("RootPanel"); - } - } + RaisePropertyChanging( "RootPanel" ); + if( _rootPanel != null && + _rootPanel.Parent == this ) + _rootPanel.Parent = null; + _rootPanel = value; + + if( _rootPanel == null ) + _rootPanel = new LayoutPanel( new LayoutDocumentPane() ); + + if( _rootPanel != null ) + _rootPanel.Parent = this; + RaisePropertyChanged( "RootPanel" ); } + } + } - #endregion + #endregion - #region TopSide + #region TopSide - private LayoutAnchorSide _topSide = null; - public LayoutAnchorSide TopSide + private LayoutAnchorSide _topSide = null; + public LayoutAnchorSide TopSide + { + get + { + return _topSide; + } + set + { + if( _topSide != value ) { - get { return _topSide; } - set - { - if (_topSide != value) - { - RaisePropertyChanging("TopSide"); - _topSide = value; - if (_topSide != null) - _topSide.Parent = this; - RaisePropertyChanged("TopSide"); - } - } + RaisePropertyChanging( "TopSide" ); + _topSide = value; + if( _topSide != null ) + _topSide.Parent = this; + RaisePropertyChanged( "TopSide" ); } + } + } - #endregion + #endregion - #region RightSide + #region RightSide - private LayoutAnchorSide _rightSide; - public LayoutAnchorSide RightSide + private LayoutAnchorSide _rightSide; + public LayoutAnchorSide RightSide + { + get + { + return _rightSide; + } + set + { + if( _rightSide != value ) { - get { return _rightSide; } - set - { - if (_rightSide != value) - { - RaisePropertyChanging("RightSide"); - _rightSide = value; - if (_rightSide != null) - _rightSide.Parent = this; - RaisePropertyChanged("RightSide"); - } - } + RaisePropertyChanging( "RightSide" ); + _rightSide = value; + if( _rightSide != null ) + _rightSide.Parent = this; + RaisePropertyChanged( "RightSide" ); } + } + } - #endregion + #endregion - #region LeftSide + #region LeftSide - private LayoutAnchorSide _leftSide = null; - public LayoutAnchorSide LeftSide + private LayoutAnchorSide _leftSide = null; + public LayoutAnchorSide LeftSide + { + get + { + return _leftSide; + } + set + { + if( _leftSide != value ) { - get { return _leftSide; } - set - { - if (_leftSide != value) - { - RaisePropertyChanging("LeftSide"); - _leftSide = value; - if (_leftSide != null) - _leftSide.Parent = this; - RaisePropertyChanged("LeftSide"); - } - } + RaisePropertyChanging( "LeftSide" ); + _leftSide = value; + if( _leftSide != null ) + _leftSide.Parent = this; + RaisePropertyChanged( "LeftSide" ); } + } + } - #endregion + #endregion - #region BottomSide + #region BottomSide - private LayoutAnchorSide _bottomSide = null; - public LayoutAnchorSide BottomSide + private LayoutAnchorSide _bottomSide = null; + public LayoutAnchorSide BottomSide + { + get + { + return _bottomSide; + } + set + { + if( _bottomSide != value ) { - get { return _bottomSide; } - set - { - if (_bottomSide != value) - { - RaisePropertyChanging("BottomSide"); - _bottomSide = value; - if (_bottomSide != null) - _bottomSide.Parent = this; - RaisePropertyChanged("BottomSide"); - } - } + RaisePropertyChanging( "BottomSide" ); + _bottomSide = value; + if( _bottomSide != null ) + _bottomSide.Parent = this; + RaisePropertyChanged( "BottomSide" ); } + } + } - #endregion + #endregion - #region FloatingWindows - ObservableCollection _floatingWindows = null; + #region FloatingWindows + ObservableCollection _floatingWindows = null; - public ObservableCollection FloatingWindows + public ObservableCollection FloatingWindows + { + get + { + if( _floatingWindows == null ) { - get - { - if (_floatingWindows == null) - { - _floatingWindows = new ObservableCollection(); - _floatingWindows.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(_floatingWindows_CollectionChanged); - } - - return _floatingWindows; - } + _floatingWindows = new ObservableCollection(); + _floatingWindows.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler( _floatingWindows_CollectionChanged ); } - void _floatingWindows_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) - { - if (e.OldItems != null && (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || - e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace)) - { - foreach (LayoutFloatingWindow element in e.OldItems) - { - if (element.Parent == this) - element.Parent = null; - } - } - - if (e.NewItems != null && (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || - e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace)) - { - foreach (LayoutFloatingWindow element in e.NewItems) - element.Parent = this; - } - } - #endregion - - #region HiddenAnchorables - - ObservableCollection _hiddenAnchorables = null; + return _floatingWindows; + } + } - public ObservableCollection Hidden + void _floatingWindows_CollectionChanged( object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e ) + { + if( e.OldItems != null && ( e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace ) ) + { + foreach( LayoutFloatingWindow element in e.OldItems ) { - get - { - if (_hiddenAnchorables == null) - { - _hiddenAnchorables = new ObservableCollection(); - _hiddenAnchorables.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(_hiddenAnchorables_CollectionChanged); - } - - return _hiddenAnchorables; - } + if( element.Parent == this ) + element.Parent = null; } + } + + if( e.NewItems != null && ( e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace ) ) + { + foreach( LayoutFloatingWindow element in e.NewItems ) + element.Parent = this; + } + } + #endregion - void _hiddenAnchorables_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) - { - if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || - e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace) - { - if (e.OldItems != null) - { - foreach (LayoutAnchorable element in e.OldItems) - { - if (element.Parent == this) - element.Parent = null; - } - } - } - - if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || - e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace) - { - if (e.NewItems != null) - { - foreach (LayoutAnchorable element in e.NewItems) - { - if (element.Parent != this) - { - if (element.Parent != null) - element.Parent.RemoveChild(element); - element.Parent = this; - } - - } - } - } - - - - } + #region HiddenAnchorables - #endregion + ObservableCollection _hiddenAnchorables = null; - #region Children - public IEnumerable Children + public ObservableCollection Hidden + { + get + { + if( _hiddenAnchorables == null ) { - get - { - if (RootPanel != null) - yield return RootPanel; - if (_floatingWindows != null) - { - foreach (var floatingWindow in _floatingWindows) - yield return floatingWindow; - } - if (TopSide != null) - yield return TopSide; - if (RightSide != null) - yield return RightSide; - if (BottomSide != null) - yield return BottomSide; - if (LeftSide != null) - yield return LeftSide; - if (_hiddenAnchorables != null) - { - foreach (var hiddenAnchorable in _hiddenAnchorables) - yield return hiddenAnchorable; - } - } + _hiddenAnchorables = new ObservableCollection(); + _hiddenAnchorables.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler( _hiddenAnchorables_CollectionChanged ); } - public void RemoveChild(ILayoutElement element) - { - if (element == RootPanel) - RootPanel = null; - else if (_floatingWindows != null && _floatingWindows.Contains(element)) - _floatingWindows.Remove(element as LayoutFloatingWindow); - else if (_hiddenAnchorables != null && _hiddenAnchorables.Contains(element)) - _hiddenAnchorables.Remove(element as LayoutAnchorable); - else if (element == TopSide) - TopSide = null; - else if (element == RightSide) - RightSide = null; - else if (element == BottomSide) - BottomSide = null; - else if (element == LeftSide) - LeftSide = null; - } + return _hiddenAnchorables; + } + } - public void ReplaceChild(ILayoutElement oldElement, ILayoutElement newElement) + void _hiddenAnchorables_CollectionChanged( object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e ) + { + if( e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace ) + { + if( e.OldItems != null ) { - if (oldElement == RootPanel) - RootPanel = (LayoutPanel)newElement; - else if (_floatingWindows != null && _floatingWindows.Contains(oldElement)) - { - int index = _floatingWindows.IndexOf(oldElement as LayoutFloatingWindow); - _floatingWindows.Remove(oldElement as LayoutFloatingWindow); - _floatingWindows.Insert(index, newElement as LayoutFloatingWindow); - } - else if (_hiddenAnchorables != null && _hiddenAnchorables.Contains(oldElement)) - { - int index = _hiddenAnchorables.IndexOf(oldElement as LayoutAnchorable); - _hiddenAnchorables.Remove(oldElement as LayoutAnchorable); - _hiddenAnchorables.Insert(index, newElement as LayoutAnchorable); - } - else if (oldElement == TopSide) - TopSide = (LayoutAnchorSide)newElement; - else if (oldElement == RightSide) - RightSide = (LayoutAnchorSide)newElement; - else if (oldElement == BottomSide) - BottomSide = (LayoutAnchorSide)newElement; - else if (oldElement == LeftSide) - LeftSide = (LayoutAnchorSide)newElement; + foreach( LayoutAnchorable element in e.OldItems ) + { + if( element.Parent == this ) + element.Parent = null; + } } + } - public int ChildrenCount + if( e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace ) + { + if( e.NewItems != null ) { - get + foreach( LayoutAnchorable element in e.NewItems ) + { + if( element.Parent != this ) { - return 5 + - (_floatingWindows != null ? _floatingWindows.Count : 0) + - (_hiddenAnchorables != null ? _hiddenAnchorables.Count : 0); + if( element.Parent != null ) + element.Parent.RemoveChild( element ); + element.Parent = this; } - } - #endregion - - #region ActiveContent - - [field:NonSerialized] - private WeakReference _activeContent = null; - private bool _activeContentSet = false; - [XmlIgnore] - public LayoutContent ActiveContent - { - get { return _activeContent.GetValueOrDefault(); } - set - { - var currentValue = ActiveContent; - if (currentValue != value) - { - InternalSetActiveContent(currentValue, value); - } - } + } } + } - void InternalSetActiveContent(LayoutContent currentValue, LayoutContent newActiveContent) - { - RaisePropertyChanging("ActiveContent"); - if (currentValue != null) - currentValue.IsActive = false; - _activeContent = new WeakReference(newActiveContent); - currentValue = ActiveContent; - if (currentValue != null) - currentValue.IsActive = true; - RaisePropertyChanged("ActiveContent"); - _activeContentSet = currentValue != null; - if (currentValue != null) - { - if (currentValue.Parent is LayoutDocumentPane || currentValue is LayoutDocument) - LastFocusedDocument = currentValue; - } - else - LastFocusedDocument = null; - } - void UpdateActiveContentProperty() - { - var activeContent = ActiveContent; - if (_activeContentSet && (activeContent == null || activeContent.Root != this)) - { - _activeContentSet = false; - InternalSetActiveContent(activeContent, null); - } - } - #endregion - #region LastFocusedDocument + } - [field: NonSerialized] - private WeakReference _lastFocusedDocument = null; - [field: NonSerialized] - private bool _lastFocusedDocumentSet = false; + #endregion - [XmlIgnore] - public LayoutContent LastFocusedDocument + #region Children + public IEnumerable Children + { + get + { + if( RootPanel != null ) + yield return RootPanel; + if( _floatingWindows != null ) { - get { return _lastFocusedDocument.GetValueOrDefault(); } - private set - { - var currentValue = LastFocusedDocument; - if (currentValue != value) - { - RaisePropertyChanging("LastFocusedDocument"); - if (currentValue != null) - currentValue.IsLastFocusedDocument = false; - _lastFocusedDocument = new WeakReference(value); - currentValue = LastFocusedDocument; - if (currentValue != null) - currentValue.IsLastFocusedDocument = true; - _lastFocusedDocumentSet = currentValue != null; - RaisePropertyChanged("LastFocusedDocument"); - } - } + foreach( var floatingWindow in _floatingWindows ) + yield return floatingWindow; } - - #endregion - - #region Manager - - - [NonSerialized] - private DockingManager _manager = null; - - [XmlIgnore] - public DockingManager Manager + if( TopSide != null ) + yield return TopSide; + if( RightSide != null ) + yield return RightSide; + if( BottomSide != null ) + yield return BottomSide; + if( LeftSide != null ) + yield return LeftSide; + if( _hiddenAnchorables != null ) { - get { return _manager; } - internal set - { - if (_manager != value) - { - RaisePropertyChanging("Manager"); - _manager = value; - RaisePropertyChanged("Manager"); - } - } + foreach( var hiddenAnchorable in _hiddenAnchorables ) + yield return hiddenAnchorable; } + } + } + public void RemoveChild( ILayoutElement element ) + { + if( element == RootPanel ) + RootPanel = null; + else if( _floatingWindows != null && _floatingWindows.Contains( element ) ) + _floatingWindows.Remove( element as LayoutFloatingWindow ); + else if( _hiddenAnchorables != null && _hiddenAnchorables.Contains( element ) ) + _hiddenAnchorables.Remove( element as LayoutAnchorable ); + else if( element == TopSide ) + TopSide = null; + else if( element == RightSide ) + RightSide = null; + else if( element == BottomSide ) + BottomSide = null; + else if( element == LeftSide ) + LeftSide = null; - #endregion - - #region CollectGarbage + } - /// - /// Removes any empty container not directly referenced by other layout items - /// - public void CollectGarbage() - { - bool exitFlag = true; + public void ReplaceChild( ILayoutElement oldElement, ILayoutElement newElement ) + { + if( oldElement == RootPanel ) + RootPanel = ( LayoutPanel )newElement; + else if( _floatingWindows != null && _floatingWindows.Contains( oldElement ) ) + { + int index = _floatingWindows.IndexOf( oldElement as LayoutFloatingWindow ); + _floatingWindows.Remove( oldElement as LayoutFloatingWindow ); + _floatingWindows.Insert( index, newElement as LayoutFloatingWindow ); + } + else if( _hiddenAnchorables != null && _hiddenAnchorables.Contains( oldElement ) ) + { + int index = _hiddenAnchorables.IndexOf( oldElement as LayoutAnchorable ); + _hiddenAnchorables.Remove( oldElement as LayoutAnchorable ); + _hiddenAnchorables.Insert( index, newElement as LayoutAnchorable ); + } + else if( oldElement == TopSide ) + TopSide = ( LayoutAnchorSide )newElement; + else if( oldElement == RightSide ) + RightSide = ( LayoutAnchorSide )newElement; + else if( oldElement == BottomSide ) + BottomSide = ( LayoutAnchorSide )newElement; + else if( oldElement == LeftSide ) + LeftSide = ( LayoutAnchorSide )newElement; + } - #region collect empty panes - do - { - exitFlag = true; - - //for each content that references via PreviousContainer a disconnected Pane set the property to null - foreach (var content in this.Descendents().OfType().Where(c => c.PreviousContainer != null && - (c.PreviousContainer.Parent == null || c.PreviousContainer.Parent.Root != this))) - { - content.PreviousContainer = null; - } - - //for each pane that is empty - foreach (var emptyPane in this.Descendents().OfType().Where(p => p.ChildrenCount == 0)) - { - //...set null any reference coming from contents not yet hosted in a floating window - foreach (var contentReferencingEmptyPane in this.Descendents().OfType() - .Where(c => ((ILayoutPreviousContainer)c).PreviousContainer == emptyPane && !c.IsFloating)) - { - if (contentReferencingEmptyPane is LayoutAnchorable && - !((LayoutAnchorable)contentReferencingEmptyPane).IsVisible) - continue; - - ((ILayoutPreviousContainer)contentReferencingEmptyPane).PreviousContainer = null; - contentReferencingEmptyPane.PreviousContainerIndex = -1; - } - - //...if this pane is the only documentpane present in the layout than skip it - if (emptyPane is LayoutDocumentPane && - this.Descendents().OfType().Count(c => c != emptyPane) == 0) - continue; - - //...if this empty panes is not referenced by anyone, than removes it from its parent container - if (!this.Descendents().OfType().Any(c => c.PreviousContainer == emptyPane)) - { - var parentGroup = emptyPane.Parent as ILayoutContainer; - parentGroup.RemoveChild(emptyPane); - exitFlag = false; - break; - } - } - - if (!exitFlag) - { - //removes any empty anchorable pane group - foreach (var emptyPaneGroup in this.Descendents().OfType().Where(p => p.ChildrenCount == 0)) - { - var parentGroup = emptyPaneGroup.Parent as ILayoutContainer; - parentGroup.RemoveChild(emptyPaneGroup); - exitFlag = false; - break; - } - } - - if (!exitFlag) - { - //removes any empty layout panel - foreach (var emptyPaneGroup in this.Descendents().OfType().Where(p => p.ChildrenCount == 0)) - { - var parentGroup = emptyPaneGroup.Parent as ILayoutContainer; - parentGroup.RemoveChild(emptyPaneGroup); - exitFlag = false; - break; - } - } - - if (!exitFlag) - { - //removes any empty floating window - foreach (var emptyPaneGroup in this.Descendents().OfType().Where(p => p.ChildrenCount == 0)) - { - var parentGroup = emptyPaneGroup.Parent as ILayoutContainer; - parentGroup.RemoveChild(emptyPaneGroup); - exitFlag = false; - break; - } - } - - if (!exitFlag) - { - //removes any empty anchor group - foreach (var emptyPaneGroup in this.Descendents().OfType().Where(p => p.ChildrenCount == 0)) - { - var parentGroup = emptyPaneGroup.Parent as ILayoutContainer; - parentGroup.RemoveChild(emptyPaneGroup); - exitFlag = false; - break; - } - } + public int ChildrenCount + { + get + { + return 5 + + ( _floatingWindows != null ? _floatingWindows.Count : 0 ) + + ( _hiddenAnchorables != null ? _hiddenAnchorables.Count : 0 ); + } + } + #endregion - } - while (!exitFlag); - #endregion + #region ActiveContent - #region collapse single child anchorable pane groups - do - { - exitFlag = true; - //for each pane that is empty - foreach (var paneGroupToCollapse in this.Descendents().OfType().Where(p => p.ChildrenCount == 1 && p.Children[0] is LayoutAnchorablePaneGroup).ToArray()) - { - var singleChild = paneGroupToCollapse.Children[0] as LayoutAnchorablePaneGroup; - paneGroupToCollapse.Orientation = singleChild.Orientation; - paneGroupToCollapse.RemoveChild(singleChild); - while (singleChild.ChildrenCount > 0) - { - paneGroupToCollapse.InsertChildAt( - paneGroupToCollapse.ChildrenCount, singleChild.Children[0]); - } - - exitFlag = false; - break; - } + [field: NonSerialized] + private WeakReference _activeContent = null; + private bool _activeContentSet = false; - } - while (!exitFlag); + [XmlIgnore] + public LayoutContent ActiveContent + { + get + { + return _activeContent.GetValueOrDefault(); + } + set + { + var currentValue = ActiveContent; + if( currentValue != value ) + { + InternalSetActiveContent( currentValue, value ); + } + } + } + void InternalSetActiveContent( LayoutContent currentValue, LayoutContent newActiveContent ) + { + RaisePropertyChanging( "ActiveContent" ); + if( currentValue != null ) + currentValue.IsActive = false; + _activeContent = new WeakReference( newActiveContent ); + currentValue = ActiveContent; + if( currentValue != null ) + currentValue.IsActive = true; + RaisePropertyChanged( "ActiveContent" ); + _activeContentSet = currentValue != null; + if( currentValue != null ) + { + if( currentValue.Parent is LayoutDocumentPane || currentValue is LayoutDocument ) + LastFocusedDocument = currentValue; + } + else + LastFocusedDocument = null; + } + void UpdateActiveContentProperty() + { + var activeContent = ActiveContent; + if( _activeContentSet && ( activeContent == null || activeContent.Root != this ) ) + { + _activeContentSet = false; + InternalSetActiveContent( activeContent, null ); + } + } + #endregion - #endregion + #region LastFocusedDocument - #region collapse single child document pane groups - do - { - exitFlag = true; - //for each pane that is empty - foreach (var paneGroupToCollapse in this.Descendents().OfType().Where(p => p.ChildrenCount == 1 && p.Children[0] is LayoutDocumentPaneGroup).ToArray()) - { - var singleChild = paneGroupToCollapse.Children[0] as LayoutDocumentPaneGroup; - paneGroupToCollapse.Orientation = singleChild.Orientation; - paneGroupToCollapse.RemoveChild(singleChild); - while (singleChild.ChildrenCount > 0) - { - paneGroupToCollapse.InsertChildAt( - paneGroupToCollapse.ChildrenCount, singleChild.Children[0]); - } - - exitFlag = false; - break; - } + [field: NonSerialized] + private WeakReference _lastFocusedDocument = null; + [field: NonSerialized] + private bool _lastFocusedDocumentSet = false; - } - while (!exitFlag); - - - - #endregion - - //do - //{ - // exitFlag = true; - // //for each panel that has only one child - // foreach( var panelToCollapse in this.Descendents().OfType().Where( p => p.ChildrenCount == 1 && p.Children[ 0 ] is LayoutPanel ).ToArray() ) - // { - // var singleChild = panelToCollapse.Children[ 0 ] as LayoutPanel; - // panelToCollapse.Orientation = singleChild.Orientation; - // panelToCollapse.RemoveChild( singleChild ); - // ILayoutPanelElement[] singleChildChildren = new ILayoutPanelElement[ singleChild.ChildrenCount ]; - // singleChild.Children.CopyTo( singleChildChildren, 0 ); - // while( singleChild.ChildrenCount > 0 ) - // { - // panelToCollapse.InsertChildAt( - // panelToCollapse.ChildrenCount, singleChildChildren[ panelToCollapse.ChildrenCount ] ); - // } - - // exitFlag = false; - // break; - // } - - //} - //while( !exitFlag ); - - #region Update ActiveContent and LastFocusedDocument properties - UpdateActiveContentProperty(); - #endregion -#if DEBUG - System.Diagnostics.Debug.Assert( - !this.Descendents().OfType().Any(a => a.ChildrenCount == 0 && a.IsVisible)); -#if TRACE - RootPanel.ConsoleDump(4); -#endif -#endif + [XmlIgnore] + public LayoutContent LastFocusedDocument + { + get + { + return _lastFocusedDocument.GetValueOrDefault(); + } + private set + { + var currentValue = LastFocusedDocument; + if( currentValue != value ) + { + RaisePropertyChanging( "LastFocusedDocument" ); + if( currentValue != null ) + currentValue.IsLastFocusedDocument = false; + _lastFocusedDocument = new WeakReference( value ); + currentValue = LastFocusedDocument; + if( currentValue != null ) + currentValue.IsLastFocusedDocument = true; + _lastFocusedDocumentSet = currentValue != null; + RaisePropertyChanged( "LastFocusedDocument" ); } + } + } - #endregion + #endregion - public event EventHandler Updated; + #region Manager - internal void FireLayoutUpdated() - { - if (Updated != null) - Updated(this, EventArgs.Empty); - } - #region LayoutElement Added/Removed events + [NonSerialized] + private DockingManager _manager = null; - internal void OnLayoutElementAdded(LayoutElement element) + [XmlIgnore] + public DockingManager Manager + { + get + { + return _manager; + } + internal set + { + if( _manager != value ) { - if (ElementAdded != null) - ElementAdded(this, new LayoutElementEventArgs(element)); + RaisePropertyChanging( "Manager" ); + _manager = value; + RaisePropertyChanged( "Manager" ); } + } + } - public event EventHandler ElementAdded; + #endregion - internal void OnLayoutElementRemoved(LayoutElement element) - { - if (element.Descendents().OfType().Any(c => c == LastFocusedDocument)) - LastFocusedDocument = null; - if (element.Descendents().OfType().Any(c => c == ActiveContent)) - ActiveContent = null; - if (ElementRemoved != null) - ElementRemoved(this, new LayoutElementEventArgs(element)); - } + #region CollectGarbage - public event EventHandler ElementRemoved; + /// + /// Removes any empty container not directly referenced by other layout items + /// + public void CollectGarbage() + { + bool exitFlag = true; - #endregion + #region collect empty panes + do + { + exitFlag = true; - public XmlSchema GetSchema() + //for each content that references via PreviousContainer a disconnected Pane set the property to null + foreach( var content in this.Descendents().OfType().Where( c => c.PreviousContainer != null && + ( c.PreviousContainer.Parent == null || c.PreviousContainer.Parent.Root != this ) ) ) { - return null; + content.PreviousContainer = null; } - public void ReadXml( XmlReader reader ) + //for each pane that is empty + foreach( var emptyPane in this.Descendents().OfType().Where( p => p.ChildrenCount == 0 ) ) { - reader.MoveToContent(); - if( reader.IsEmptyElement ) + //...set null any reference coming from contents not yet hosted in a floating window + foreach( var contentReferencingEmptyPane in this.Descendents().OfType() + .Where( c => ( ( ILayoutPreviousContainer )c ).PreviousContainer == emptyPane && !c.IsFloating ) ) { - reader.Read(); - return; - } + if( contentReferencingEmptyPane is LayoutAnchorable && + !( ( LayoutAnchorable )contentReferencingEmptyPane ).IsVisible ) + continue; - var layoutPanelElements = ReadRootPanel( reader ); - if( layoutPanelElements != null ) - { - //Create the RootPanel with the first child - RootPanel = new LayoutPanel( layoutPanelElements.First() ); - //Add all children to RootPanel - for( int i = 1; i < layoutPanelElements.Count; ++i ) - { - RootPanel.Children.Add( layoutPanelElements[ i ] ); - } + ( ( ILayoutPreviousContainer )contentReferencingEmptyPane ).PreviousContainer = null; + contentReferencingEmptyPane.PreviousContainerIndex = -1; } - TopSide = ( LayoutAnchorSide )ReadElement( reader ); - if( TopSide != null ) - { - TopSide.Children.Add( ( LayoutAnchorGroup )ReadElement( reader ) ); - reader.Read(); - } - RightSide = ( LayoutAnchorSide )ReadElement( reader ); - if( RightSide != null ) - { - RightSide.Children.Add( ( LayoutAnchorGroup )ReadElement( reader ) ); - reader.Read(); - } - LeftSide = ( LayoutAnchorSide )ReadElement( reader ); - if( LeftSide != null ) + //...if this pane is the only documentpane present in the layout than skip it + if( emptyPane is LayoutDocumentPane && + this.Descendents().OfType().Count( c => c != emptyPane ) == 0 ) + continue; + + //...if this empty panes is not referenced by anyone, than removes it from its parent container + if( !this.Descendents().OfType().Any( c => c.PreviousContainer == emptyPane ) ) { - LeftSide.Children.Add( ( LayoutAnchorGroup )ReadElement( reader ) ); - reader.Read(); + var parentGroup = emptyPane.Parent as ILayoutContainer; + parentGroup.RemoveChild( emptyPane ); + exitFlag = false; + break; } - BottomSide = ( LayoutAnchorSide )ReadElement( reader ); - if( BottomSide != null ) + } + + if( !exitFlag ) + { + //removes any empty anchorable pane group + foreach( var emptyPaneGroup in this.Descendents().OfType().Where( p => p.ChildrenCount == 0 ) ) { - BottomSide.Children.Add( ( LayoutAnchorGroup )ReadElement( reader ) ); - reader.Read(); + var parentGroup = emptyPaneGroup.Parent as ILayoutContainer; + parentGroup.RemoveChild( emptyPaneGroup ); + exitFlag = false; + break; } + } - FloatingWindows.Clear(); - var floatingWindows = ReadElementList( reader ); - foreach( var floatingWindow in floatingWindows ) + if( !exitFlag ) + { + //removes any empty layout panel + foreach( var emptyPaneGroup in this.Descendents().OfType().Where( p => p.ChildrenCount == 0 ) ) { - FloatingWindows.Add( ( LayoutFloatingWindow )floatingWindow ); + var parentGroup = emptyPaneGroup.Parent as ILayoutContainer; + parentGroup.RemoveChild( emptyPaneGroup ); + exitFlag = false; + break; } + } - Hidden.Clear(); - var hidden = ReadElementList( reader ); - foreach( var hiddenObject in hidden ) + if( !exitFlag ) + { + //removes any empty floating window + foreach( var emptyPaneGroup in this.Descendents().OfType().Where( p => p.ChildrenCount == 0 ) ) { - Hidden.Add( ( LayoutAnchorable )hiddenObject ); + var parentGroup = emptyPaneGroup.Parent as ILayoutContainer; + parentGroup.RemoveChild( emptyPaneGroup ); + exitFlag = false; + break; } } - private List ReadRootPanel( XmlReader reader ) + if( !exitFlag ) { - var result = new List(); - - var startElementName = reader.LocalName; - reader.Read(); - if( reader.LocalName.Equals(startElementName) && (reader.NodeType == XmlNodeType.EndElement) ) + //removes any empty anchor group + foreach( var emptyPaneGroup in this.Descendents().OfType().Where( p => p.ChildrenCount == 0 ) ) { - return null; + var parentGroup = emptyPaneGroup.Parent as ILayoutContainer; + parentGroup.RemoveChild( emptyPaneGroup ); + exitFlag = false; + break; } + } - while( reader.NodeType == XmlNodeType.Whitespace ) + } + while( !exitFlag ); + #endregion + + #region collapse single child anchorable pane groups + do + { + exitFlag = true; + //for each pane that is empty + foreach( var paneGroupToCollapse in this.Descendents().OfType().Where( p => p.ChildrenCount == 1 && p.Children[ 0 ] is LayoutAnchorablePaneGroup ).ToArray() ) + { + var singleChild = paneGroupToCollapse.Children[ 0 ] as LayoutAnchorablePaneGroup; + paneGroupToCollapse.Orientation = singleChild.Orientation; + paneGroupToCollapse.RemoveChild( singleChild ); + while( singleChild.ChildrenCount > 0 ) { - reader.Read(); + paneGroupToCollapse.InsertChildAt( + paneGroupToCollapse.ChildrenCount, singleChild.Children[ 0 ] ); } - if( reader.LocalName.Equals("RootPanel")) - { - reader.Read(); + exitFlag = false; + break; + } - while( true ) - { - //Read all RootPanel children - var element = ReadElement( reader ) as ILayoutPanelElement; - if( element != null ) - { - result.Add( element ); - } - else if( reader.NodeType == XmlNodeType.EndElement ) - { - break; - } - } - } + } + while( !exitFlag ); - reader.ReadEndElement(); - return result; - } - private List ReadElementList( XmlReader reader ) - { - var resultList = new List(); + #endregion - if( reader.IsEmptyElement ) + #region collapse single child document pane groups + do + { + exitFlag = true; + //for each pane that is empty + foreach( var paneGroupToCollapse in this.Descendents().OfType().Where( p => p.ChildrenCount == 1 && p.Children[ 0 ] is LayoutDocumentPaneGroup ).ToArray() ) + { + var singleChild = paneGroupToCollapse.Children[ 0 ] as LayoutDocumentPaneGroup; + paneGroupToCollapse.Orientation = singleChild.Orientation; + paneGroupToCollapse.RemoveChild( singleChild ); + while( singleChild.ChildrenCount > 0 ) { - reader.Read(); - return resultList; + paneGroupToCollapse.InsertChildAt( + paneGroupToCollapse.ChildrenCount, singleChild.Children[ 0 ] ); } - var startElementName = reader.LocalName; - reader.Read(); - if( reader.LocalName.Equals(startElementName) && (reader.NodeType == XmlNodeType.EndElement) ) - { - return null; - } + exitFlag = false; + break; + } - while( reader.NodeType == XmlNodeType.Whitespace ) - { - reader.Read(); - } + } + while( !exitFlag ); - while( true ) - { - var result = ReadElement( reader ) as LayoutFloatingWindow; - if( result == null ) - { - break; - } - resultList.Add( result ); - } - reader.ReadEndElement(); + #endregion + + //do + //{ + // exitFlag = true; + // //for each panel that has only one child + // foreach( var panelToCollapse in this.Descendents().OfType().Where( p => p.ChildrenCount == 1 && p.Children[ 0 ] is LayoutPanel ).ToArray() ) + // { + // var singleChild = panelToCollapse.Children[ 0 ] as LayoutPanel; + // panelToCollapse.Orientation = singleChild.Orientation; + // panelToCollapse.RemoveChild( singleChild ); + // ILayoutPanelElement[] singleChildChildren = new ILayoutPanelElement[ singleChild.ChildrenCount ]; + // singleChild.Children.CopyTo( singleChildChildren, 0 ); + // while( singleChild.ChildrenCount > 0 ) + // { + // panelToCollapse.InsertChildAt( + // panelToCollapse.ChildrenCount, singleChildChildren[ panelToCollapse.ChildrenCount ] ); + // } + + // exitFlag = false; + // break; + // } + + //} + //while( !exitFlag ); + + #region Update ActiveContent and LastFocusedDocument properties + UpdateActiveContentProperty(); + #endregion +#if DEBUG + System.Diagnostics.Debug.Assert( + !this.Descendents().OfType().Any( a => a.ChildrenCount == 0 && a.IsVisible ) ); +#if TRACE + RootPanel.ConsoleDump(4); +#endif +#endif + } + + #endregion + + public event EventHandler Updated; + + internal void FireLayoutUpdated() + { + if( Updated != null ) + Updated( this, EventArgs.Empty ); + } + + #region LayoutElement Added/Removed events - return resultList; + internal void OnLayoutElementAdded( LayoutElement element ) + { + if( ElementAdded != null ) + ElementAdded( this, new LayoutElementEventArgs( element ) ); + } + + public event EventHandler ElementAdded; + + internal void OnLayoutElementRemoved( LayoutElement element ) + { + if( element.Descendents().OfType().Any( c => c == LastFocusedDocument ) ) + LastFocusedDocument = null; + if( element.Descendents().OfType().Any( c => c == ActiveContent ) ) + ActiveContent = null; + if( ElementRemoved != null ) + ElementRemoved( this, new LayoutElementEventArgs( element ) ); + } + + public event EventHandler ElementRemoved; + + #endregion + + public XmlSchema GetSchema() + { + return null; + } + + public void ReadXml( XmlReader reader ) + { + reader.MoveToContent(); + if( reader.IsEmptyElement ) + { + reader.Read(); + return; + } + + var layoutPanelElements = ReadRootPanel( reader ); + if( layoutPanelElements != null ) + { + RootPanel = new LayoutPanel(); + //Add all children to RootPanel + for( int i = 0; i < layoutPanelElements.Count; ++i ) + { + RootPanel.Children.Add( layoutPanelElements[ i ] ); } + } + + TopSide = new LayoutAnchorSide(); + if( ReadElement( reader ) != null ) + { + FillLayoutAnchorSide( reader, TopSide ); + } + RightSide = new LayoutAnchorSide(); + if( ReadElement( reader ) != null ) + { + FillLayoutAnchorSide( reader, RightSide ); + } + LeftSide = new LayoutAnchorSide(); + if( ReadElement( reader ) != null ) + { + FillLayoutAnchorSide( reader, LeftSide ); + } + BottomSide = new LayoutAnchorSide(); + if( ReadElement( reader ) != null ) + { + FillLayoutAnchorSide( reader, BottomSide ); + } + + FloatingWindows.Clear(); + var floatingWindows = ReadElementList( reader ); + foreach( var floatingWindow in floatingWindows ) + { + FloatingWindows.Add( ( LayoutFloatingWindow )floatingWindow ); + } + + Hidden.Clear(); + var hidden = ReadElementList( reader ); + foreach( var hiddenObject in hidden ) + { + Hidden.Add( ( LayoutAnchorable )hiddenObject ); + } + } + + private void FillLayoutAnchorSide( XmlReader reader, LayoutAnchorSide layoutAnchorSide ) + { + var result = new List(); - private object ReadElement( XmlReader reader ) + while( true ) + { + //Read all layoutAnchorSide children + var element = ReadElement( reader ) as LayoutAnchorGroup; + if( element != null ) { - if( reader.NodeType == XmlNodeType.EndElement ) - { - return null; - } + result.Add( element ); + } + else if( reader.NodeType == XmlNodeType.EndElement ) + { + break; + } + } - while( reader.NodeType == XmlNodeType.Whitespace ) - { - reader.Read(); - } + reader.ReadEndElement(); + foreach( var las in result ) + { + layoutAnchorSide.Children.Add( las ); + } + } - XmlSerializer serializer; - switch( reader.LocalName ) - { - case "LayoutAnchorablePaneGroup": - serializer = new XmlSerializer( typeof( LayoutAnchorablePaneGroup ) ); - break; - case "LayoutAnchorablePane": - serializer = new XmlSerializer( typeof( LayoutAnchorablePane ) ); - break; - case "LayoutAnchorable": - serializer = new XmlSerializer( typeof( LayoutAnchorable ) ); - break; - case "LayoutDocumentPaneGroup": - serializer = new XmlSerializer( typeof( LayoutDocumentPaneGroup ) ); - break; - case "LayoutDocumentPane": - serializer = new XmlSerializer( typeof( LayoutDocumentPane ) ); - break; - case "LayoutDocument": - serializer = new XmlSerializer( typeof( LayoutDocument ) ); - break; - case "LayoutAnchorGroup": - serializer = new XmlSerializer( typeof( LayoutAnchorGroup ) ); - break; - case "LayoutPanel": - serializer = new XmlSerializer( typeof( LayoutPanel ) ); - break; - case "LayoutDocumentFloatingWindow": - serializer = new XmlSerializer( typeof( LayoutDocumentFloatingWindow ) ); - break; - case "LayoutAnchorableFloatingWindow": - serializer = new XmlSerializer( typeof( LayoutAnchorableFloatingWindow ) ); - break; - case "LeftSide": - case "RightSide": - case "TopSide": - case "BottomSide": - if( reader.IsEmptyElement ) - { - reader.Read(); - return null; - } - reader.Read(); - return new LayoutAnchorSide(); - default: - var type = LayoutRoot.FindType( reader.LocalName ); - if( type == null ) - { - throw new ArgumentException( "AvalonDock.LayoutRoot doesn't know how to deserialize " + reader.LocalName ); - } - serializer = new XmlSerializer( type ); - break; - } + private List ReadRootPanel( XmlReader reader ) + { + var result = new List(); - return serializer.Deserialize( reader ); - } + var startElementName = reader.LocalName; + reader.Read(); + if( reader.LocalName.Equals( startElementName ) && ( reader.NodeType == XmlNodeType.EndElement ) ) + { + return null; + } + + while( reader.NodeType == XmlNodeType.Whitespace ) + { + reader.Read(); + } + + if( reader.LocalName.Equals( "RootPanel" ) ) + { + reader.Read(); - public void WriteXml( XmlWriter writer ) + while( true ) { - writer.WriteStartElement( "RootPanel" ); - if( RootPanel != null ) + //Read all RootPanel children + var element = ReadElement( reader ) as ILayoutPanelElement; + if( element != null ) { - RootPanel.WriteXml( writer ); + result.Add( element ); } - writer.WriteEndElement(); - - writer.WriteStartElement( "TopSide" ); - if( TopSide != null ) + else if( reader.NodeType == XmlNodeType.EndElement ) { - TopSide.WriteXml( writer ); + break; } - writer.WriteEndElement(); + } + } - writer.WriteStartElement( "RightSide" ); - if( RightSide != null ) - { - RightSide.WriteXml( writer ); - } - writer.WriteEndElement(); + reader.ReadEndElement(); - writer.WriteStartElement( "LeftSide" ); - if( LeftSide != null ) - { - LeftSide.WriteXml( writer ); - } - writer.WriteEndElement(); + return result; + } - writer.WriteStartElement( "BottomSide" ); - if( BottomSide != null ) - { - BottomSide.WriteXml( writer ); - } - writer.WriteEndElement(); + private List ReadElementList( XmlReader reader ) + { + var resultList = new List(); + + if( reader.IsEmptyElement ) + { + reader.Read(); + return resultList; + } + + var startElementName = reader.LocalName; + reader.Read(); + if( reader.LocalName.Equals( startElementName ) && ( reader.NodeType == XmlNodeType.EndElement ) ) + { + return null; + } + + while( reader.NodeType == XmlNodeType.Whitespace ) + { + reader.Read(); + } + + while( true ) + { + var result = ReadElement( reader ) as LayoutFloatingWindow; + if( result == null ) + { + break; + } + + resultList.Add( result ); + } - // Write all floating windows (can be LayoutDocumentFloatingWindow or LayoutAnchorableFloatingWindow). - // To prevent "can not create instance of abstract type", the type is retrieved with GetType().Name - writer.WriteStartElement( "FloatingWindows" ); - foreach( var layoutFloatingWindow in FloatingWindows ) + reader.ReadEndElement(); + + return resultList; + } + + private object ReadElement( XmlReader reader ) + { + if( reader.NodeType == XmlNodeType.EndElement ) + { + return null; + } + + while( reader.NodeType == XmlNodeType.Whitespace ) + { + reader.Read(); + } + + XmlSerializer serializer; + switch( reader.LocalName ) + { + case "LayoutAnchorablePaneGroup": + serializer = new XmlSerializer( typeof( LayoutAnchorablePaneGroup ) ); + break; + case "LayoutAnchorablePane": + serializer = new XmlSerializer( typeof( LayoutAnchorablePane ) ); + break; + case "LayoutAnchorable": + serializer = new XmlSerializer( typeof( LayoutAnchorable ) ); + break; + case "LayoutDocumentPaneGroup": + serializer = new XmlSerializer( typeof( LayoutDocumentPaneGroup ) ); + break; + case "LayoutDocumentPane": + serializer = new XmlSerializer( typeof( LayoutDocumentPane ) ); + break; + case "LayoutDocument": + serializer = new XmlSerializer( typeof( LayoutDocument ) ); + break; + case "LayoutAnchorGroup": + serializer = new XmlSerializer( typeof( LayoutAnchorGroup ) ); + break; + case "LayoutPanel": + serializer = new XmlSerializer( typeof( LayoutPanel ) ); + break; + case "LayoutDocumentFloatingWindow": + serializer = new XmlSerializer( typeof( LayoutDocumentFloatingWindow ) ); + break; + case "LayoutAnchorableFloatingWindow": + serializer = new XmlSerializer( typeof( LayoutAnchorableFloatingWindow ) ); + break; + case "LeftSide": + case "RightSide": + case "TopSide": + case "BottomSide": + if( reader.IsEmptyElement ) { - writer.WriteStartElement( layoutFloatingWindow.GetType().Name ); - layoutFloatingWindow.WriteXml( writer ); - writer.WriteEndElement(); + reader.Read(); + return null; } - writer.WriteEndElement(); - - writer.WriteStartElement( "Hidden" ); - foreach( var layoutAnchorable in Hidden ) + return reader.Read(); + default: + var type = LayoutRoot.FindType( reader.LocalName ); + if( type == null ) { - layoutAnchorable.WriteXml( writer ); + throw new ArgumentException( "AvalonDock.LayoutRoot doesn't know how to deserialize " + reader.LocalName ); } - writer.WriteEndElement(); - } + serializer = new XmlSerializer( type ); + break; + } - internal static Type FindType( string name ) + return serializer.Deserialize( reader ); + } + + public void WriteXml( XmlWriter writer ) + { + writer.WriteStartElement( "RootPanel" ); + if( RootPanel != null ) + { + RootPanel.WriteXml( writer ); + } + writer.WriteEndElement(); + + writer.WriteStartElement( "TopSide" ); + if( TopSide != null ) + { + TopSide.WriteXml( writer ); + } + writer.WriteEndElement(); + + writer.WriteStartElement( "RightSide" ); + if( RightSide != null ) + { + RightSide.WriteXml( writer ); + } + writer.WriteEndElement(); + + writer.WriteStartElement( "LeftSide" ); + if( LeftSide != null ) + { + LeftSide.WriteXml( writer ); + } + writer.WriteEndElement(); + + writer.WriteStartElement( "BottomSide" ); + if( BottomSide != null ) + { + BottomSide.WriteXml( writer ); + } + writer.WriteEndElement(); + + // Write all floating windows (can be LayoutDocumentFloatingWindow or LayoutAnchorableFloatingWindow). + // To prevent "can not create instance of abstract type", the type is retrieved with GetType().Name + writer.WriteStartElement( "FloatingWindows" ); + foreach( var layoutFloatingWindow in FloatingWindows ) + { + writer.WriteStartElement( layoutFloatingWindow.GetType().Name ); + layoutFloatingWindow.WriteXml( writer ); + writer.WriteEndElement(); + } + writer.WriteEndElement(); + + writer.WriteStartElement( "Hidden" ); + foreach( var layoutAnchorable in Hidden ) + { + layoutAnchorable.WriteXml( writer ); + } + writer.WriteEndElement(); + } + + internal static Type FindType( string name ) + { + foreach( var assembly in AppDomain.CurrentDomain.GetAssemblies() ) + { + foreach( var type in assembly.GetTypes() ) { - foreach( var assembly in AppDomain.CurrentDomain.GetAssemblies() ) - { - foreach( var type in assembly.GetTypes() ) - { - if( type.Name.Equals( name ) ) - return type; - } - } - return null; + if( type.Name.Equals( name ) ) + return type; } + } + return null; + } #if TRACE public override void ConsoleDump(int tab) @@ -969,5 +1012,5 @@ namespace Xceed.Wpf.AvalonDock.Layout #endif - } + } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Properties/AssemblyInfo.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Properties/AssemblyInfo.cs index f82cf8c3..3800cc83 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Properties/AssemblyInfo.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Properties/AssemblyInfo.cs @@ -30,7 +30,7 @@ using System; [assembly: AssemblyCompany( "Xceed Software Inc." )] [assembly: AssemblyProduct( "Xceed Toolkit for WPF - AvalonDock" )] -[assembly: AssemblyCopyright( "Copyright (C) Xceed Software Inc. 2007-2016" )] +[assembly: AssemblyCopyright( "Copyright (C) Xceed Software Inc. 2007-2017" )] [assembly: AssemblyCulture( "" )] diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Themes/generic.xaml b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Themes/generic.xaml index b3237473..33b1c73e 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Themes/generic.xaml +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Themes/generic.xaml @@ -23,581 +23,789 @@ xmlns:avalonDockConverters="clr-namespace:Xceed.Wpf.AvalonDock.Converters" xmlns:avalonDockProperties="clr-namespace:Xceed.Wpf.AvalonDock.Properties"> - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + + - - - - - - - - + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - + + + + + + + + - + + + + + + + + + + + + + - - - - - - - - - + + + + + + - - - - - - - - - - - - + + + + + + + + + - - - - - + + + + + + + + + + + + - + + + + + - - - + - - - - - - - - - - - - - - - + + + + - - - + + + + + + + + + + + + + + + + + - - - + + + + - - - + + + + - - - - - - - + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + - - - + - + - + + + + + - + + + + + - + + + + + - + + + + + - + + + - + + + + + + - + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + - - - - + + + + - + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Xceed.Wpf.AvalonDock.csproj b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Xceed.Wpf.AvalonDock.csproj index 5d73417a..2f447660 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Xceed.Wpf.AvalonDock.csproj +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/Xceed.Wpf.AvalonDock.csproj @@ -100,6 +100,7 @@ + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/GeneratedInternalTypeHelper.g.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/GeneratedInternalTypeHelper.g.cs new file mode 100644 index 00000000..c65238fb --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/GeneratedInternalTypeHelper.g.cs @@ -0,0 +1,2 @@ + + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/GeneratedInternalTypeHelper.g.i.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/GeneratedInternalTypeHelper.g.i.cs new file mode 100644 index 00000000..136dd1ba --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/GeneratedInternalTypeHelper.g.i.cs @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace XamlGeneratedNamespace { + + + /// + /// GeneratedInternalTypeHelper + /// + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public sealed class GeneratedInternalTypeHelper : System.Windows.Markup.InternalTypeHelper { + + /// + /// CreateInstance + /// + protected override object CreateInstance(System.Type type, System.Globalization.CultureInfo culture) { + return System.Activator.CreateInstance(type, ((System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic) + | (System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.CreateInstance)), null, null, culture); + } + + /// + /// GetPropertyValue + /// + protected override object GetPropertyValue(System.Reflection.PropertyInfo propertyInfo, object target, System.Globalization.CultureInfo culture) { + return propertyInfo.GetValue(target, System.Reflection.BindingFlags.Default, null, null, culture); + } + + /// + /// SetPropertyValue + /// + protected override void SetPropertyValue(System.Reflection.PropertyInfo propertyInfo, object target, object value, System.Globalization.CultureInfo culture) { + propertyInfo.SetValue(target, value, System.Reflection.BindingFlags.Default, null, null, culture); + } + + /// + /// CreateDelegate + /// + protected override System.Delegate CreateDelegate(System.Type delegateType, object target, string handler) { + return ((System.Delegate)(target.GetType().InvokeMember("_CreateDelegate", (System.Reflection.BindingFlags.InvokeMethod + | (System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)), null, target, new object[] { + delegateType, + handler}, null))); + } + + /// + /// AddEventHandler + /// + protected override void AddEventHandler(System.Reflection.EventInfo eventInfo, object target, System.Delegate handler) { + eventInfo.AddEventHandler(target, handler); + } + } +} + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Themes/generic.baml b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Themes/generic.baml new file mode 100644 index 00000000..22f928b7 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Themes/generic.baml differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.de.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.de.resources new file mode 100644 index 00000000..2d06a706 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.de.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.es.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.es.resources new file mode 100644 index 00000000..f0a26271 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.es.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.fr.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.fr.resources new file mode 100644 index 00000000..a624b88a Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.fr.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.hu.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.hu.resources new file mode 100644 index 00000000..5e49fd06 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.hu.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.it.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.it.resources new file mode 100644 index 00000000..77d9552c Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.it.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.pt-BR.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.pt-BR.resources new file mode 100644 index 00000000..b92e3121 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.pt-BR.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.resources new file mode 100644 index 00000000..7aaab51e Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.ro.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.ro.resources new file mode 100644 index 00000000..de139964 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.ro.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.ru.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.ru.resources new file mode 100644 index 00000000..5980151d Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.ru.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.sv.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.sv.resources new file mode 100644 index 00000000..49c61057 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.sv.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.zh-Hans.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.zh-Hans.resources new file mode 100644 index 00000000..b102a440 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.Properties.Resources.zh-Hans.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.csproj.FileListAbsolute.txt b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.csproj.FileListAbsolute.txt new file mode 100644 index 00000000..0423a185 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.csproj.FileListAbsolute.txt @@ -0,0 +1,42 @@ +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Debug\Xceed.Wpf.AvalonDock.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Debug\Xceed.Wpf.AvalonDock.pdb +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Debug\hu\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Debug\it\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Debug\fr\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Debug\es\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Debug\pt-BR\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Debug\ru\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Debug\de\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Debug\sv\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Debug\zh-Hans\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Debug\ro\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.csprojResolveAssemblyReference.cache +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\GeneratedInternalTypeHelper.g.cs +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock_MarkupCompile.cache +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock_MarkupCompile.lref +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\Themes\generic.baml +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.g.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.hu.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.it.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.fr.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.es.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.pt-BR.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.ru.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.de.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.sv.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.zh-Hans.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.Properties.Resources.ro.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.csproj.GenerateResource.Cache +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\hu\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\it\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\fr\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\es\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\pt-BR\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\ru\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\de\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\sv\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\zh-Hans\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\ro\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\Xceed.Wpf.AvalonDock.pdb diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.g.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.g.resources new file mode 100644 index 00000000..c29e0a29 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock.g.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock_MarkupCompile.lref b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock_MarkupCompile.lref new file mode 100644 index 00000000..138d068a --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Debug/Xceed.Wpf.AvalonDock_MarkupCompile.lref @@ -0,0 +1,4 @@ +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Debug\GeneratedInternalTypeHelper.g.cs + +FD:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\Themes\generic.xaml;; + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/GeneratedInternalTypeHelper.g.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/GeneratedInternalTypeHelper.g.cs new file mode 100644 index 00000000..c65238fb --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/GeneratedInternalTypeHelper.g.cs @@ -0,0 +1,2 @@ + + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/GeneratedInternalTypeHelper.g.i.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/GeneratedInternalTypeHelper.g.i.cs new file mode 100644 index 00000000..136dd1ba --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/GeneratedInternalTypeHelper.g.i.cs @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace XamlGeneratedNamespace { + + + /// + /// GeneratedInternalTypeHelper + /// + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public sealed class GeneratedInternalTypeHelper : System.Windows.Markup.InternalTypeHelper { + + /// + /// CreateInstance + /// + protected override object CreateInstance(System.Type type, System.Globalization.CultureInfo culture) { + return System.Activator.CreateInstance(type, ((System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic) + | (System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.CreateInstance)), null, null, culture); + } + + /// + /// GetPropertyValue + /// + protected override object GetPropertyValue(System.Reflection.PropertyInfo propertyInfo, object target, System.Globalization.CultureInfo culture) { + return propertyInfo.GetValue(target, System.Reflection.BindingFlags.Default, null, null, culture); + } + + /// + /// SetPropertyValue + /// + protected override void SetPropertyValue(System.Reflection.PropertyInfo propertyInfo, object target, object value, System.Globalization.CultureInfo culture) { + propertyInfo.SetValue(target, value, System.Reflection.BindingFlags.Default, null, null, culture); + } + + /// + /// CreateDelegate + /// + protected override System.Delegate CreateDelegate(System.Type delegateType, object target, string handler) { + return ((System.Delegate)(target.GetType().InvokeMember("_CreateDelegate", (System.Reflection.BindingFlags.InvokeMethod + | (System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)), null, target, new object[] { + delegateType, + handler}, null))); + } + + /// + /// AddEventHandler + /// + protected override void AddEventHandler(System.Reflection.EventInfo eventInfo, object target, System.Delegate handler) { + eventInfo.AddEventHandler(target, handler); + } + } +} + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Themes/generic.baml b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Themes/generic.baml new file mode 100644 index 00000000..7f04cc18 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Themes/generic.baml differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.de.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.de.resources new file mode 100644 index 00000000..2d06a706 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.de.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.es.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.es.resources new file mode 100644 index 00000000..f0a26271 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.es.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.fr.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.fr.resources new file mode 100644 index 00000000..a624b88a Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.fr.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.hu.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.hu.resources new file mode 100644 index 00000000..5e49fd06 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.hu.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.it.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.it.resources new file mode 100644 index 00000000..77d9552c Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.it.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.pt-BR.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.pt-BR.resources new file mode 100644 index 00000000..b92e3121 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.pt-BR.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.resources new file mode 100644 index 00000000..7aaab51e Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.ro.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.ro.resources new file mode 100644 index 00000000..de139964 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.ro.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.ru.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.ru.resources new file mode 100644 index 00000000..5980151d Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.ru.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.sv.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.sv.resources new file mode 100644 index 00000000..49c61057 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.sv.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.zh-Hans.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.zh-Hans.resources new file mode 100644 index 00000000..b102a440 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.Properties.Resources.zh-Hans.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.csproj.FileListAbsolute.txt b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.csproj.FileListAbsolute.txt new file mode 100644 index 00000000..10353340 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.csproj.FileListAbsolute.txt @@ -0,0 +1,42 @@ +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Release\Xceed.Wpf.AvalonDock.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Release\Xceed.Wpf.AvalonDock.pdb +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Release\hu\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Release\it\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Release\fr\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Release\es\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Release\pt-BR\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Release\ru\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Release\de\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Release\sv\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Release\zh-Hans\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\bin\Release\ro\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\Xceed.Wpf.AvalonDock.csprojResolveAssemblyReference.cache +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\GeneratedInternalTypeHelper.g.cs +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\Xceed.Wpf.AvalonDock_MarkupCompile.cache +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\Xceed.Wpf.AvalonDock_MarkupCompile.lref +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\Themes\generic.baml +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\Xceed.Wpf.AvalonDock.g.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\Xceed.Wpf.AvalonDock.Properties.Resources.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\Xceed.Wpf.AvalonDock.Properties.Resources.hu.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\Xceed.Wpf.AvalonDock.Properties.Resources.it.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\Xceed.Wpf.AvalonDock.Properties.Resources.fr.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\Xceed.Wpf.AvalonDock.Properties.Resources.es.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\Xceed.Wpf.AvalonDock.Properties.Resources.pt-BR.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\Xceed.Wpf.AvalonDock.Properties.Resources.ru.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\Xceed.Wpf.AvalonDock.Properties.Resources.de.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\Xceed.Wpf.AvalonDock.Properties.Resources.sv.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\Xceed.Wpf.AvalonDock.Properties.Resources.zh-Hans.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\Xceed.Wpf.AvalonDock.Properties.Resources.ro.resources +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\Xceed.Wpf.AvalonDock.csproj.GenerateResource.Cache +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\hu\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\it\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\fr\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\es\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\pt-BR\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\ru\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\de\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\sv\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\zh-Hans\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\ro\Xceed.Wpf.AvalonDock.resources.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\Xceed.Wpf.AvalonDock.dll +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\Xceed.Wpf.AvalonDock.pdb diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.g.resources b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.g.resources new file mode 100644 index 00000000..709a3188 Binary files /dev/null and b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock.g.resources differ diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock_MarkupCompile.lref b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock_MarkupCompile.lref new file mode 100644 index 00000000..d95c9eaa --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.AvalonDock/obj/Release/Xceed.Wpf.AvalonDock_MarkupCompile.lref @@ -0,0 +1,4 @@ +D:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\obj\Release\GeneratedInternalTypeHelper.g.cs + +FD:\Dev\ExtendedWPFToolkit\Release\3.3.0\OpenSource\Generated\Src\Xceed.Wpf.AvalonDock\Themes\generic.xaml;; + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(DataVirtualization)/VirtualList.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(DataVirtualization)/VirtualList.cs index 2f3526f4..d0eecffc 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(DataVirtualization)/VirtualList.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(DataVirtualization)/VirtualList.cs @@ -26,9 +26,6 @@ namespace Xceed.Wpf.DataGrid { internal class VirtualList : IList, IList, INotifyCollectionChanged, IDisposable { - - #region CONSTRUCTORS - public VirtualList( VirtualPageManager pagingManager ) : this( pagingManager, -1 ) { @@ -46,8 +43,6 @@ namespace Xceed.Wpf.DataGrid m_virtualCount = virtualCount; } - #endregion CONSTRUCTORS - #region VirtualPagingManager Property public VirtualPageManager PagingManager @@ -58,9 +53,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion VirtualPagingManager Property - - + #endregion #region VirtualCount Property @@ -78,27 +71,89 @@ namespace Xceed.Wpf.DataGrid } } - #endregion VirtualCount Property + #endregion - internal int IndexOf( object item ) + #region TableOfContent Property + + internal VirtualListTableOfContent TableOfContent { - if( ( item == null ) || ( this.IsDisposed ) ) - return -1; + get + { + return m_tableOfContent; + } + } - EmptyDataItem emptyDataItem = item as EmptyDataItem; + #endregion - if( emptyDataItem != null ) + #region VirtualPagingManager Property + + internal VirtualPageManager VirtualPagingManager + { + get { - if( ( emptyDataItem.ParentVirtualList == this ) && ( emptyDataItem.Index < m_virtualCount ) ) - return emptyDataItem.Index; + 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." ); - return -1; + m_pagingManager = value; } + } - return m_tableOfContent.IndexOf( item ); + #endregion + + #region IsDisposed Property + + internal bool IsDisposed + { + get + { + return m_flags[ ( int )VirtualItemBookFlags.Disposed ]; + } + private set + { + m_flags[ ( int )VirtualItemBookFlags.Disposed ] = value; + } } - #region PUBLIC METHODS + #endregion + + #region IsRestarting Property + + internal bool IsRestarting + { + get + { + return m_flags[ ( int )VirtualItemBookFlags.Restarting ]; + } + private set + { + m_flags[ ( int )VirtualItemBookFlags.Restarting ] = value; + } + } + + #endregion + + #region HasPagePendingCommit Property + + internal bool HasPagePendingCommit + { + get + { + foreach( VirtualPage page in m_tableOfContent.VirtualPages ) + { + if( page.IsCommitPending ) + return true; + } + + return false; + } + } + + #endregion #if DEBUG public override string ToString() @@ -119,41 +174,24 @@ namespace Xceed.Wpf.DataGrid } #endif - #endregion PUBLIC METHODS - + internal int IndexOf( object item ) + { + if( ( item == null ) || ( this.IsDisposed ) ) + return -1; - #region INTERNAL PROPERTIES + EmptyDataItem emptyDataItem = item as EmptyDataItem; - internal VirtualListTableOfContent TableOfContent - { - get + if( emptyDataItem != null ) { - return m_tableOfContent; - } - } + if( ( emptyDataItem.ParentVirtualList == this ) && ( emptyDataItem.Index < m_virtualCount ) ) + return emptyDataItem.Index; - internal VirtualPageManager VirtualPagingManager - { - get - { - return m_pagingManager; + return -1; } - 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; - } + return m_tableOfContent.IndexOf( item ); } - - #endregion INTERNAL PROPERTIES - - - #region INTERNAL METHODS - internal bool IsPageDirty( int index ) { VirtualPage page = this.GetPageOrDefaultForItemIndex( index, true ); @@ -220,24 +258,6 @@ namespace Xceed.Wpf.DataGrid virtualizedItemInfo = page.GetVirtualizedItemInfoAtIndex( index ); Debug.Assert( virtualizedItemInfo != null ); - - - //if( ( virtualizedItemInfo == null ) && ( createPageIfLineNotFound ) ) - //{ - // // No VirtualizedItemInfo was found at the requested index. - // LinkedListNode 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 ) { @@ -259,7 +279,9 @@ namespace Xceed.Wpf.DataGrid 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 ); } @@ -277,7 +299,6 @@ namespace Xceed.Wpf.DataGrid 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(); @@ -287,8 +308,7 @@ namespace Xceed.Wpf.DataGrid 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) + // The VirtualList is disposed or part of a PagingManager that will be disposed (only disconnected when dispose is required) if( !this.PagingManager.IsConnected ) return; @@ -297,8 +317,7 @@ namespace Xceed.Wpf.DataGrid double preemptivePageQueryRatio = m_pagingManager.PreemptivePageQueryRatio; int pageSize = m_pagingManager.PageSize; - double pageRatio = ( preemptivePageQueryRatio > 0.5 ) ? 0.5 : - ( preemptivePageQueryRatio < 0.0 ) ? 0 : preemptivePageQueryRatio; + double pageRatio = ( preemptivePageQueryRatio > 0.5 ) ? 0.5 : ( preemptivePageQueryRatio < 0.0 ) ? 0 : preemptivePageQueryRatio; double boundariesItemCount = ( pageRatio * pageSize ); @@ -319,8 +338,7 @@ namespace Xceed.Wpf.DataGrid { 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. + // 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 ) @@ -332,7 +350,6 @@ namespace Xceed.Wpf.DataGrid } } - internal bool IsAsyncCommitQueuedForItem( object item ) { VirtualPage virtualPage; @@ -351,7 +368,9 @@ namespace Xceed.Wpf.DataGrid Debug.Assert( page.ParentVirtualList == this ); if( page.IsDirty ) + { m_pagingManager.QueueCommitData( page ); + } } } @@ -361,6 +380,7 @@ namespace Xceed.Wpf.DataGrid return; Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "Restart VirtualList requested, checking for pages to commit or abort..." ); + this.IsRestarting = true; m_pagingManager.OnVirtualListRestarting( this ); @@ -373,10 +393,8 @@ namespace Xceed.Wpf.DataGrid } 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 + // 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-- ) @@ -385,16 +403,16 @@ namespace Xceed.Wpf.DataGrid 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 + // 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 ); } @@ -402,21 +420,16 @@ namespace Xceed.Wpf.DataGrid 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. + // 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 + // 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" ); @@ -424,22 +437,16 @@ namespace Xceed.Wpf.DataGrid } } - #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) + // 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. + // 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 ); @@ -469,18 +476,12 @@ namespace Xceed.Wpf.DataGrid Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "Replaced TOC items/index for page: " + page.ToString() ); - this.OnCollectionChanged( new NotifyCollectionChangedEventArgs( - NotifyCollectionChangedAction.Replace, - fetchedItems, oldItems, - asyncQueryInfo.StartIndex ) ); + 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. + // 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 ) ); } } @@ -492,7 +493,7 @@ namespace Xceed.Wpf.DataGrid 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. + // We do not want to move the page we are about to 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 ); @@ -535,70 +536,16 @@ namespace Xceed.Wpf.DataGrid } 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; @@ -630,12 +577,14 @@ namespace Xceed.Wpf.DataGrid 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 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; } @@ -676,7 +625,9 @@ namespace Xceed.Wpf.DataGrid Debug.Assert( page != null ); if( ( page != null ) && ( page.IsLocked ) ) + { lockedPages.Add( page ); + } } return lockedPages; @@ -689,42 +640,22 @@ namespace Xceed.Wpf.DataGrid 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 m_restartingPages = new List(); - private VirtualPageManager m_pagingManager; - private BitVector32 m_flags; - private int m_virtualCount; - private VirtualListTableOfContent m_tableOfContent; - - #endregion PRIVATE FIELDS - - - #region PRIVATE NESTED ENUMS + var handler = this.CollectionChanged; + if( handler == null ) + return; - [Flags] - private enum VirtualItemBookFlags - { - Restarting = 1, - Disposed = 2, + handler.Invoke( this, e ); } - #endregion PRIVATE NESTED ENUMS - - #region IList Members int IList.IndexOf( object item ) @@ -925,8 +856,6 @@ namespace Xceed.Wpf.DataGrid #endregion - - #region IDisposable Members public void Dispose() @@ -935,6 +864,7 @@ namespace Xceed.Wpf.DataGrid if( m_tableOfContent != null ) { Debug.Assert( m_tableOfContent.VirtualPages.Count == 0 ); + m_tableOfContent.Dispose(); m_tableOfContent = null; } @@ -945,5 +875,18 @@ namespace Xceed.Wpf.DataGrid } #endregion + + private List m_restartingPages = new List(); + private VirtualPageManager m_pagingManager; + private BitVector32 m_flags; + private int m_virtualCount; + private VirtualListTableOfContent m_tableOfContent; + + [Flags] + private enum VirtualItemBookFlags + { + Restarting = 1, + Disposed = 2, + } } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(DataVirtualization)/VirtualPage.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(DataVirtualization)/VirtualPage.cs index fa5edec0..2dc5900c 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(DataVirtualization)/VirtualPage.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(DataVirtualization)/VirtualPage.cs @@ -16,19 +16,14 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Specialized; using System.Diagnostics; using System.Windows.Threading; -using System.Collections.Specialized; namespace Xceed.Wpf.DataGrid { - internal class VirtualPage - : List, IDisposable + internal class VirtualPage : List, IDisposable { - #region CONSTRUCTORS - internal static VirtualPage CreateEmptyPage( VirtualList parentVirtualList, int startSourceIndex, int entryCount ) { if( parentVirtualList == null ) @@ -76,9 +71,7 @@ namespace Xceed.Wpf.DataGrid this.IsFilled = true; } - #endregion CONSTRUCTORS - - #region RemoveAfterOperation + #region RemoveAfterOperation Property public bool RemoveAfterOperation { @@ -118,7 +111,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion IsEmpty Property + #endregion #region IsFilled Property @@ -137,7 +130,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion IsFilled Property + #endregion #region IsDisposed Read-Only Property @@ -165,7 +158,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion IsCommitPending Property + #endregion #region IsDirty Property @@ -188,7 +181,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion IsDirty Property + #endregion #region IsLocked Property @@ -200,9 +193,9 @@ namespace Xceed.Wpf.DataGrid } } - #endregion IsLocked Property + #endregion - #region IsRemovable + #region IsRemovable Property public bool IsRemovable { @@ -213,7 +206,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion IsRemovable + #endregion #region ParentVirtualList Property @@ -225,8 +218,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion ParentVirtualList Property - + #endregion #region StartDataIndex Property @@ -238,7 +230,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion StartDataIndex Property + #endregion #region EndDataIndex Property @@ -250,10 +242,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion EndDataIndex Property - - - #region PUBLIC METHODS + #endregion public VirtualizedItemInfo GetVirtualizedItemInfoAtIndex( int sourceIndex ) { @@ -271,8 +260,9 @@ namespace Xceed.Wpf.DataGrid string representation = string.Empty; if( !this.IsFilled ) + { representation += "Fill Pending - "; - + } if( this.IsEmpty ) { @@ -301,131 +291,14 @@ namespace Xceed.Wpf.DataGrid return items; } - #endregion PUBLIC METHODS - - - #region PRIVATE CALLBACKS - - private void AsyncQueryInfo_BuiltInAbort( AsyncQueryInfo queryInfo ) - { - if( this.IsDisposed ) - return; - - Debug.Assert( ( this.ParentVirtualList != null ) || ( this.ParentVirtualList.PagingManager != null ) ); - - this.ParentVirtualList.PagingManager.OnBuiltInAbort( this, queryInfo ); - this.IsAborting = false; - } - - private void AsyncQueryInfo_BeginQueryItems( AsyncQueryInfo queryInfo ) - { - if( this.IsDisposed ) - return; - - Debug.Assert( ( this.ParentVirtualList != null ) || ( this.ParentVirtualList.PagingManager != null ) ); - - this.ParentVirtualList.PagingManager.OnQueryItems( this, queryInfo ); - } - - private void AsyncQueryInfo_AbortQueryItems( AsyncQueryInfo queryInfo ) - { - if( this.IsDisposed ) - return; - - Debug.Assert( ( this.ParentVirtualList != null ) || ( this.ParentVirtualList.PagingManager != null ) ); - - 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.ParentVirtualList != null ) || ( this.ParentVirtualList.PagingManager != null ) ); - Debug.Assert( !this.IsAborting ); - this.ParentVirtualList.PagingManager.OnQueryItemsCompleted( this, queryInfo, fetchedItems ); - - if( this.ParentVirtualList.IsRestarting ) - this.Restart(); - } - - private void AsyncQueryInfo_QueryErrorChanged( AsyncQueryInfo queryInfo ) - { - if( this.IsDisposed ) - return; - - Debug.Assert( ( this.ParentVirtualList != null ) || ( this.ParentVirtualList.PagingManager != null ) ); - - this.ParentVirtualList.PagingManager.OnQueryErrorChanged( this, queryInfo ); - - if( this.ParentVirtualList.IsRestarting ) - this.Restart(); - } - - private void AsyncCommitInfo_BeginCommitItems( AsyncCommitInfo commitInfo ) - { - if( this.IsDisposed ) - return; - - Debug.Assert( ( this.ParentVirtualList != null ) || ( this.ParentVirtualList.PagingManager != null ) ); - - this.ParentVirtualList.PagingManager.OnCommitItems( this, commitInfo ); - } - - private void AsyncCommitInfo_EndCommitItems( AsyncCommitInfo commitInfo ) - { - if( this.IsDisposed ) - return; - - Debug.Assert( ( this.ParentVirtualList != null ) || ( this.ParentVirtualList.PagingManager != null ) ); - - this.ParentVirtualList.PagingManager.OnCommitItemsCompleted( this, commitInfo ); - - if( this.ParentVirtualList.IsRestarting ) - this.Restart(); - } - - private void AsyncCommitInfo_CommitErrorChanged( AsyncCommitInfo commitInfo ) - { - if( this.IsDisposed ) - return; - - Debug.Assert( ( this.ParentVirtualList != null ) || ( this.ParentVirtualList.PagingManager != null ) ); - - this.ParentVirtualList.PagingManager.OnCommitErrorChanged( this, commitInfo ); - - if( this.ParentVirtualList.IsRestarting ) - this.Restart(); - } - - #endregion PRIVATE CALLBACKS - - #region INTERNAL METHODS - - /// - /// 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. - /// internal bool LockPage() { m_lockCount++; - // Returns True if the page just became locked or False if the call simply incremented the lock count. + // Returns True if the page just became locked (and is not up for removal) or False if the call simply incremented the lock count. return m_lockCount == 1; } - /// - /// 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. - /// internal bool UnlockPage() { if( m_lockCount > 0 ) @@ -442,7 +315,7 @@ namespace Xceed.Wpf.DataGrid return false; } - // Returns True if the page just became unlocked or False if the call simply decremented the lock count. + // Returns True if the page just became unlocked (and is up for removal) or False if the call simply decremented the lock count. return m_lockCount == 0; } @@ -455,7 +328,16 @@ namespace Xceed.Wpf.DataGrid if( m_asyncQueryInfo != null ) { - this.IsAborting = true; + // This method can be reentered by another thread, while it's already being processed, with the result that the AbortQuery delegate may not be trigged by the CollectionView, + // and hence the client code not prevented it must abort the query/operation/connection. + lock( this ) + { + if( this.IsAborting ) + return; + + this.IsAborting = true; + } + m_asyncQueryInfo.AbortQuery(); } } @@ -463,7 +345,6 @@ namespace Xceed.Wpf.DataGrid internal void QueueQueryData( Dispatcher dispatcher ) { Debug.Assert( !this.IsDisposed ); - Debug.Assert( m_asyncQueryInfo == null ); m_asyncQueryInfo = new AsyncQueryInfo( @@ -485,12 +366,12 @@ namespace Xceed.Wpf.DataGrid // 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. + // 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; } @@ -511,6 +392,7 @@ namespace Xceed.Wpf.DataGrid } this.IsFilled = true; + Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "Page Filled - " + this.ToString() ); } @@ -529,6 +411,7 @@ namespace Xceed.Wpf.DataGrid if( ( virtualizedItemInfo.IsDirty ) && ( !this.IsAsyncCommitInfoQueuedForItem( virtualizedItemInfo.DataItem ) ) ) { Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "QueueCommitData for page " + this.ToString() + " and index " + virtualizedItemInfo.Index ); + dirtyItemInfoNotAlreadyPendingCommit.Add( virtualizedItemInfo ); } } @@ -587,6 +470,7 @@ namespace Xceed.Wpf.DataGrid if( !this.IsRestarting ) { Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "Restart VirtualPage requested for " + this.ToString() ); + this.IsRestarting = true; this.ParentVirtualList.OnVirtualPageRestarting( this ); } @@ -600,78 +484,160 @@ namespace Xceed.Wpf.DataGrid internal void EndRestart() { - // VirtualPage will be disposed by the VirtualPageManager - // when it removes the page from is m_pageNodeList + // 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 + private void AsyncQueryInfo_BuiltInAbort( AsyncQueryInfo queryInfo ) + { + if( this.IsDisposed ) + return; - #region PRIVATE METHODS + Debug.Assert( ( this.ParentVirtualList != null ) || ( this.ParentVirtualList.PagingManager != null ) ); - private int SourceIndexToPageEntryIndex( int sourceIndex ) + this.ParentVirtualList.PagingManager.OnBuiltInAbort( this, queryInfo ); + this.IsAborting = false; + } + + private void AsyncQueryInfo_BeginQueryItems( AsyncQueryInfo queryInfo ) { - if( ( this.Count != 0 ) && ( ( sourceIndex >= m_startDataIndex ) && ( sourceIndex <= this.EndDataIndex ) ) ) - return sourceIndex - m_startDataIndex; + if( this.IsDisposed ) + return; - return -1; + Debug.Assert( ( this.ParentVirtualList != null ) || ( this.ParentVirtualList.PagingManager != null ) ); + + this.ParentVirtualList.PagingManager.OnQueryItems( this, queryInfo ); } - private bool ContainsItem( object item ) + private void AsyncQueryInfo_AbortQueryItems( AsyncQueryInfo queryInfo ) { - int count = this.Count; + if( this.IsDisposed ) + return; - for( int i = 0; i < count; i++ ) + Debug.Assert( ( this.ParentVirtualList != null ) || ( this.ParentVirtualList.PagingManager != null ) ); + + 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 ) { - if( this[ i ].DataItem == item ) - return true; + this.Restart(); } + } - return false; + private void AsyncQueryInfo_EndQueryItems( AsyncQueryInfo queryInfo, object[] fetchedItems ) + { + if( this.IsDisposed ) + return; + + Debug.Assert( ( this.ParentVirtualList != null ) || ( this.ParentVirtualList.PagingManager != null ) ); + Debug.Assert( !this.IsAborting ); + + // The page can be removed when the CollectionView raises a CollectionChanged and the selection is consequently updated, so make sure to lock it until the update operation is done. + this.LockPage(); + + this.ParentVirtualList.PagingManager.OnQueryItemsCompleted( this, queryInfo, fetchedItems ); + + this.UnlockPage(); + + if( this.ParentVirtualList.IsRestarting ) + { + this.Restart(); + } } - #endregion PRIVATE METHODS + private void AsyncQueryInfo_QueryErrorChanged( AsyncQueryInfo queryInfo ) + { + if( this.IsDisposed ) + return; - #region PRIVATE FIELDS + Debug.Assert( ( this.ParentVirtualList != null ) || ( this.ParentVirtualList.PagingManager != null ) ); - private BitVector32 m_flags; + this.ParentVirtualList.PagingManager.OnQueryErrorChanged( this, queryInfo ); - private int m_startDataIndex; - private int m_lockCount; + if( this.ParentVirtualList.IsRestarting ) + { + this.Restart(); + } + } - private VirtualList m_parentVirtualList; + private void AsyncCommitInfo_BeginCommitItems( AsyncCommitInfo commitInfo ) + { + if( this.IsDisposed ) + return; - private AsyncQueryInfo m_asyncQueryInfo; - private List m_asyncCommitInfoList; + Debug.Assert( ( this.ParentVirtualList != null ) || ( this.ParentVirtualList.PagingManager != null ) ); - #endregion PRIVATE FIELDS + this.ParentVirtualList.PagingManager.OnCommitItems( this, commitInfo ); + } - #region PRIVATE NESTED ENUMS + private void AsyncCommitInfo_EndCommitItems( AsyncCommitInfo commitInfo ) + { + if( this.IsDisposed ) + return; - [Flags] - private enum VirtualItemPageFlags + Debug.Assert( ( this.ParentVirtualList != null ) || ( this.ParentVirtualList.PagingManager != null ) ); + + this.ParentVirtualList.PagingManager.OnCommitItemsCompleted( this, commitInfo ); + + // Make sure the page has not been removed by the previous call before accessing the parent virtual list. + if( !this.IsDisposed && this.ParentVirtualList.IsRestarting ) + { + this.Restart(); + } + } + + private void AsyncCommitInfo_CommitErrorChanged( AsyncCommitInfo commitInfo ) { - IsFilled = 1, - IsDisposed = 2, + if( this.IsDisposed ) + return; + + Debug.Assert( ( this.ParentVirtualList != null ) || ( this.ParentVirtualList.PagingManager != null ) ); + + this.ParentVirtualList.PagingManager.OnCommitErrorChanged( this, commitInfo ); + + if( this.ParentVirtualList.IsRestarting ) + { + this.Restart(); + } + } + + private int SourceIndexToPageEntryIndex( int sourceIndex ) + { + if( ( this.Count != 0 ) && ( ( sourceIndex >= m_startDataIndex ) && ( sourceIndex <= this.EndDataIndex ) ) ) + return sourceIndex - m_startDataIndex; + + return -1; } - #endregion PRIVATE NESTED ENUMS + 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; + } #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 + // We must dispose the AsyncQueryInfo to be sure it does not root this VirtualPage instance m_asyncQueryInfo.Dispose(); m_asyncQueryInfo = null; } @@ -684,5 +650,22 @@ namespace Xceed.Wpf.DataGrid } #endregion + + private BitVector32 m_flags; + + private int m_startDataIndex; + private int m_lockCount; + + private VirtualList m_parentVirtualList; + + public AsyncQueryInfo m_asyncQueryInfo; + private List m_asyncCommitInfoList; + + [Flags] + private enum VirtualItemPageFlags + { + IsFilled = 1, + IsDisposed = 2, + } } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(DataVirtualization)/VirtualPageManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(DataVirtualization)/VirtualPageManager.cs index 41bde2fd..2969c085 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(DataVirtualization)/VirtualPageManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(DataVirtualization)/VirtualPageManager.cs @@ -16,29 +16,20 @@ 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; +using System.Diagnostics; +using System.Windows.Threading; 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 ) + public VirtualPageManager( Dispatcher dispatcher, int pageSize, int maxRealizedItemCount, double preemptivePageQueryRatio ) { if( dispatcher == null ) throw new ArgumentNullException( "dispatcher" ); @@ -64,9 +55,7 @@ namespace Xceed.Wpf.DataGrid this.IsConnected = true; } - #endregion CONSTRUCTORS - - #region DISPATCHER PROPERTY + #region Dispatcher Property public Dispatcher Dispatcher { @@ -74,8 +63,7 @@ namespace Xceed.Wpf.DataGrid private set; } - #endregion DISPATCHER PROPERTY - + #endregion #region PageSize Property @@ -87,7 +75,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion PageSize Property + #endregion #region MaxRealizedItemCount Property @@ -99,7 +87,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion MaxRealizedItemCount Property + #endregion #region PreemptivePageQueryRatio Property @@ -115,7 +103,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion PreemptivePageQueryRatio Property + #endregion #region ManagedLists Property @@ -124,15 +112,17 @@ namespace Xceed.Wpf.DataGrid get { if( m_readOnlyManagedLists == null ) + { m_readOnlyManagedLists = new ReadOnlyCollection( m_managedLists ); + } return m_readOnlyManagedLists; } } - #endregion ManagedLists Property + #endregion - #region IsDisposed Private Property + #region IsDisposed Property protected bool IsDisposed { @@ -148,7 +138,47 @@ namespace Xceed.Wpf.DataGrid #endregion - #region RestartingManager Private Property + #region EstimatedTotalPageCount Property + + internal int EstimatedTotalPageCount + { + get + { + return m_maxRemovablePageCount + VirtualPageManager.EstimatedLockedPageCount; + } + } + + #endregion + + #region Version Property + + internal int Version + { + get + { + return m_version; + } + } + + #endregion + + #region IsConnected Property + + internal bool IsConnected + { + get + { + return m_flags[ ( int )VirtualPageManagerFlags.IsConnected ]; + } + private set + { + m_flags[ ( int )VirtualPageManagerFlags.IsConnected ] = value; + } + } + + #endregion + + #region RestartingManager Property private bool RestartingManager { @@ -164,7 +194,7 @@ namespace Xceed.Wpf.DataGrid #endregion - #region ShouldRefreshAfterRestart Private Property + #region ShouldRefreshAfterRestart Property private bool ShouldRefreshAfterRestart { @@ -180,34 +210,50 @@ namespace Xceed.Wpf.DataGrid #endregion + #region LastRemovable Property - #region DATA VIRTUALIZATION METHODS - - protected virtual void OnVirtualPageManagerRestarting() + private LinkedListNode LastRemovable { + get + { + LinkedListNode 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; + } } - protected virtual void OnVirtualPageManagerRestarted( bool shouldRefresh ) + #endregion + + protected abstract int OnQueryItemCountCore( VirtualList virtualList ); + + protected virtual void OnVirtualPageManagerRestarting() { } - internal void QueueQueryData( VirtualPage page ) + protected virtual void OnVirtualPageManagerRestarted( bool shouldRefresh ) { - Debug.Assert( m_managedLists.Contains( page.ParentVirtualList ) ); - page.QueueQueryData( this.Dispatcher ); } - internal void QueueCommitData( VirtualPage page ) + protected virtual void EndRestart() { - Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "QueueCommitData for page " + page.ToString() ); - Debug.Assert( m_managedLists.Contains( page.ParentVirtualList ) ); - Debug.Assert( page.IsFilled ); - Debug.Assert( page.IsDirty ); + this.RestartingManager = false; - if( this.RestartingManager ) - this.ShouldRefreshAfterRestart = true; + Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "VirtualPageManager (" + this.GetHashCode() + ")- All virtual Lists restarted." ); - page.QueueCommitData( this.Dispatcher ); + this.OnVirtualPageManagerRestarted( this.ShouldRefreshAfterRestart ); + this.ShouldRefreshAfterRestart = false; } protected internal abstract void OnBuiltInAbort( VirtualPage virtualPage, AsyncQueryInfo queryInfo ); @@ -217,13 +263,10 @@ namespace Xceed.Wpf.DataGrid 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 ) @@ -250,174 +293,139 @@ namespace Xceed.Wpf.DataGrid { } - #endregion DATA VIRTUALIZATION METHODS - - #region PAGE MANAGEMENT - - internal List> GetUnlockedPendingFillNodes() + internal virtual void OnVirtualListRestarting( VirtualList virtualList ) { - List> unlockedPendingFillNodes = new List>(); + 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." ); + } - LinkedListNode lastUnlockedPendingFillNode = m_pageNodes.Last; + 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." ); - while( lastUnlockedPendingFillNode != null ) + if( this.RestartingManager ) { - VirtualPage page = lastUnlockedPendingFillNode.Value; - - Debug.Assert( page != null ); - - if( ( !page.IsLocked ) && ( !page.IsFilled ) ) - { - unlockedPendingFillNodes.Add( lastUnlockedPendingFillNode ); - } - - lastUnlockedPendingFillNode = lastUnlockedPendingFillNode.Previous; + m_restartingListsCount--; } - return unlockedPendingFillNodes; - } - - private LinkedListNode LastRemovable - { - get + // 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 pageNode = m_pageNodes.Last; + while( pageNode != null ) { - LinkedListNode lastRemovableNode = m_pageNodes.Last; - - while( lastRemovableNode != null ) - { - Debug.Assert( lastRemovableNode.Value != null ); + LinkedListNode previousNode = pageNode.Previous; - VirtualPage page = lastRemovableNode.Value; + if( pageNode.Value.ParentVirtualList == virtualList ) + throw new DataGridInternalException( "A VirtualPage was not remove from its parent VirtualList after it is restarted" ); - if( page.IsRemovable ) - return lastRemovableNode; + pageNode = previousNode; + } - lastRemovableNode = lastRemovableNode.Previous; - } + this.IncrementVersion(); - return lastRemovableNode; + // 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 void CleanUpAndDisposeUnused() + internal virtual void OnVirtualListPageRestarting( VirtualList virtualList, VirtualPage page ) { - // 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> unlockedPendingFillNodes = this.GetUnlockedPendingFillNodes(); - - int unlockedPendingFillCount = unlockedPendingFillNodes.Count; + Debug.Assert( m_managedLists.Contains( virtualList ) ); - for( int i = 0; i < unlockedPendingFillCount; i++ ) - { - this.QueueCommitDataOrAbortIfRequired( unlockedPendingFillNodes[ i ], true ); - } + LinkedListNode pageNode = m_pageNodes.Find( page ); - // 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. + Debug.Assert( pageNode != null ); - int removablePageItemCount = this.GetRemovablePageItemCount(); + // 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 ); + } - while( removablePageItemCount > m_maxRealizedItemCount ) - { - LinkedListNode lastRemovable = this.LastRemovable; + internal virtual void OnVirtualListPageRestarted( VirtualList virtualList, VirtualPage page ) + { + Debug.Assert( m_managedLists.Contains( virtualList ) ); + Debug.Assert( m_pageNodes.Contains( page ) ); - Debug.Assert( lastRemovable != null ); + this.RemovePage( page ); + } - removablePageItemCount -= lastRemovable.Value.Count; + internal void QueueQueryData( VirtualPage page ) + { + Debug.Assert( m_managedLists.Contains( page.ParentVirtualList ) ); - this.QueueCommitDataOrAbortIfRequired( lastRemovable, true ); - } + page.QueueQueryData( this.Dispatcher ); } - private int GetRemovablePageCount() + internal void QueueCommitData( VirtualPage page ) { - int removablePageCount = 0; - - LinkedListNode pageNode = m_pageNodes.Last; + Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "QueueCommitData for page " + page.ToString() ); + Debug.Assert( m_managedLists.Contains( page.ParentVirtualList ) ); + Debug.Assert( page.IsFilled ); + Debug.Assert( page.IsDirty ); - while( pageNode != null ) + if( this.RestartingManager ) { - VirtualPage page = pageNode.Value; - - Debug.Assert( page != null ); - - if( ( page != null ) && ( page.IsRemovable ) ) - removablePageCount++; - - pageNode = pageNode.Previous; + this.ShouldRefreshAfterRestart = true; } - return removablePageCount; + page.QueueCommitData( this.Dispatcher ); } - private int GetRemovablePageItemCount() + internal List> GetUnlockedPendingFillNodes() { - int removablePageItemCount = 0; + List> unlockedPendingFillNodes = new List>(); - LinkedListNode pageNode = m_pageNodes.Last; + LinkedListNode lastUnlockedPendingFillNode = m_pageNodes.Last; - while( pageNode != null ) + while( lastUnlockedPendingFillNode != null ) { - VirtualPage page = pageNode.Value; + VirtualPage page = lastUnlockedPendingFillNode.Value; Debug.Assert( page != null ); - if( ( page != null ) && ( page.IsRemovable ) ) + if( ( !page.IsLocked ) && ( !page.IsFilled ) ) { - removablePageItemCount += page.Count; + unlockedPendingFillNodes.Add( lastUnlockedPendingFillNode ); } - pageNode = pageNode.Previous; + lastUnlockedPendingFillNode = lastUnlockedPendingFillNode.Previous; } - return removablePageItemCount; + return unlockedPendingFillNodes; } - private void QueueCommitDataOrAbortIfRequired( - LinkedListNode pageNode, - bool removeAfterOperation ) + internal void CleanUpAndDisposeUnused() { - VirtualPage page = pageNode.Value; + // Remove the less used unlocked pages. This will also ask to save it. - // Update the flag in case this page must be removed - // after an abort or commit operation - page.RemoveAfterOperation = removeAfterOperation; + // 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. - // 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 ) ) ); + // 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> unlockedPendingFillNodes = this.GetUnlockedPendingFillNodes(); - 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 ) + int unlockedPendingFillCount = unlockedPendingFillNodes.Count; + + for( int i = 0; i < unlockedPendingFillCount; i++ ) { - // The page is not filled, we must send abort - // the QueryData for this page in case it was sent - page.AbortQueryDataOperation(); + this.QueueCommitDataOrAbortIfRequired( unlockedPendingFillNodes[ i ], true ); } - // 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 ) + // 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 ) { - this.RemovePage( page ); + LinkedListNode lastRemovable = this.LastRemovable; + + Debug.Assert( lastRemovable != null ); + + removablePageItemCount -= lastRemovable.Value.Count; + + this.QueueCommitDataOrAbortIfRequired( lastRemovable, true ); } } @@ -427,8 +435,6 @@ namespace Xceed.Wpf.DataGrid return; Debug.Assert( page != null ); - //Debug.Assert( !page.IsRestarting ); - Debug.Assert( !page.IsDirty ); // A filled page is being removed. Change the version. @@ -455,7 +461,6 @@ namespace Xceed.Wpf.DataGrid if( firstNode.Value != page ) { LinkedListNode node = m_pageNodes.Find( page ); - m_pageNodes.Remove( node ); m_pageNodes.AddFirst( node ); @@ -468,8 +473,7 @@ namespace Xceed.Wpf.DataGrid 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. + // 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 ) @@ -484,16 +488,13 @@ namespace Xceed.Wpf.DataGrid 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(); @@ -517,115 +518,6 @@ namespace Xceed.Wpf.DataGrid } } - 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 pageNode = m_pageNodes.Last; - while( pageNode != null ) - { - LinkedListNode 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 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; @@ -654,6 +546,7 @@ namespace Xceed.Wpf.DataGrid if( virtualList.IsAsyncCommitQueuedForItem( item ) ) { Debug.Assert( !( item is EmptyDataItem ), "A commit operation should not have been queued for an EmptyDataItem." ); + return true; } @@ -676,6 +569,7 @@ namespace Xceed.Wpf.DataGrid if( virtualList.IsItemDirty( item ) ) { Debug.Assert( !( item is EmptyDataItem ), "An EmptyDataItem should not have been flagged as dirty." ); + return true; } @@ -768,7 +662,9 @@ namespace Xceed.Wpf.DataGrid Debug.Assert( m_managedLists.Contains( virtualList ) ); if( !currentVirtualLists.Contains( virtualList ) ) + { currentVirtualLists.Add( virtualList ); + } pageNode = pageNode.Next; } @@ -781,67 +677,95 @@ namespace Xceed.Wpf.DataGrid } } - #endregion INTERNAL METHODS + private int GetRemovablePageCount() + { + int removablePageCount = 0; - #region PRIVATE METHODS + LinkedListNode pageNode = m_pageNodes.Last; - private void IncrementVersion() - { - unchecked + while( pageNode != null ) { - m_version++; - } - } + VirtualPage page = pageNode.Value; - #endregion PRIVATE METHODS + Debug.Assert( page != null ); - #region PRIVATE FIELDS + if( ( page != null ) && ( page.IsRemovable ) ) + { + removablePageCount++; + } - private int m_version; - private int m_restartingListsCount; + pageNode = pageNode.Previous; + } - private BitVector32 m_flags = new BitVector32(); + return removablePageCount; + } - private LinkedList m_pageNodes; + private int GetRemovablePageItemCount() + { + int removablePageItemCount = 0; - private List m_managedLists; - private ReadOnlyCollection m_readOnlyManagedLists; + LinkedListNode pageNode = m_pageNodes.Last; - private int m_pageSize; - private int m_maxRealizedItemCount; - private double m_preemptivePageQueryRatio; - private int m_maxRemovablePageCount; + while( pageNode != null ) + { + VirtualPage page = pageNode.Value; - #endregion PRIVATE FIELDS + Debug.Assert( page != null ); + if( ( page != null ) && ( page.IsRemovable ) ) + { + removablePageItemCount += page.Count; + } - #region PageInsertPosition private Enum + pageNode = pageNode.Previous; + } - internal enum PageInsertPosition - { - Front = 0, - Back = 1 + return removablePageItemCount; } - #endregion + private void QueueCommitDataOrAbortIfRequired( LinkedListNode pageNode, bool removeAfterOperation ) + { + VirtualPage page = pageNode.Value; - #region VirtualPageManagerFlags Enum + // Update the flag in case this page must be removed after an abort or commit operation + page.RemoveAfterOperation = removeAfterOperation; - private enum VirtualPageManagerFlags - { - RestartingManager = 1, - ShouldRefreshAfterRestart = 2, - IsDisposed = 4, - IsConnected = 8, + // 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 ); + } } - #endregion + private void IncrementVersion() + { + unchecked + { + m_version++; + } + } #region IDisposable Members public void Dispose() { + this.DisposeCore(); + } protected virtual void DisposeCore() @@ -860,5 +784,34 @@ namespace Xceed.Wpf.DataGrid } #endregion + + private int m_version; + private int m_restartingListsCount; + + private BitVector32 m_flags = new BitVector32(); + + private LinkedList m_pageNodes; + + private List m_managedLists; + private ReadOnlyCollection m_readOnlyManagedLists; + + private int m_pageSize; + private int m_maxRealizedItemCount; + private double m_preemptivePageQueryRatio; + private int m_maxRemovablePageCount; + + internal enum PageInsertPosition + { + Front = 0, + Back = 1 + } + + private enum VirtualPageManagerFlags + { + RestartingManager = 1, + ShouldRefreshAfterRestart = 2, + IsDisposed = 4, + IsConnected = 8, + } } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(ForeignKeys)/DataGridForeignKeyDescription.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(ForeignKeys)/DataGridForeignKeyDescription.cs index 83aaf5df..0abec623 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(ForeignKeys)/DataGridForeignKeyDescription.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(ForeignKeys)/DataGridForeignKeyDescription.cs @@ -14,7 +14,9 @@ ***********************************************************************************/ +using System; using System.Collections; +using System.Data; using System.Windows; namespace Xceed.Wpf.DataGrid @@ -23,6 +25,7 @@ namespace Xceed.Wpf.DataGrid { public DataGridForeignKeyDescription() { + this.SetForeignKeyConverter(); } #region ForeignKeyConverter Property @@ -122,5 +125,102 @@ namespace Xceed.Wpf.DataGrid } #endregion + + protected virtual void SetForeignKeyConverter() + { + this.ForeignKeyConverter = new DataGridForeignKeyConverter(); + } + + internal Type GetDataType() + { + var itemsSource = this.ItemsSource; + if( itemsSource == null ) + return null; + + var displayMemberPath = this.DisplayMemberPath; + var foreignKeyConverter = this.ForeignKeyConverter; + + if( string.IsNullOrWhiteSpace( displayMemberPath ) && ( foreignKeyConverter == null ) ) + return null; + + try + { + //Use the DisplayMemberPath or the ForeignKeyConverter to find the converted value data type, using a DataRowView or reflection. + if( ( itemsSource is DataView ) || ( itemsSource is DataTable ) ) + { + foreach( object item in itemsSource ) + { + var dataRowView = item as DataRowView; + if( dataRowView == null ) + continue; + + if( !string.IsNullOrWhiteSpace( displayMemberPath ) ) + { + var dataColumn = dataRowView.Row.Table.Columns[ displayMemberPath ]; + if( dataColumn != null ) + { + return dataColumn.DataType; + } + } + else + { + var valuePath = this.ValuePath; + if( valuePath != null ) + { + var key = dataRowView[ valuePath ]; + var value = foreignKeyConverter.GetValueFromKey( key, this ); + if( value != null ) + { + return value.GetType(); + } + } + } + } + } + else + { + foreach( object item in itemsSource ) + { + if( item == null ) + continue; + + if( !string.IsNullOrWhiteSpace( displayMemberPath ) ) + return item.GetType().GetProperty( displayMemberPath ).PropertyType; + + if( item is Enum ) + return item.GetType(); + + var valuePath = this.ValuePath; + if( valuePath != null ) + { + var key = item.GetType().GetProperty( valuePath ).GetValue( item, null ); + var value = foreignKeyConverter.GetValueFromKey( key, this ); + if( value != null ) + { + return value.GetType(); + } + } + } + } + } + catch + { + //Swallow the exception, no need to terminate the application, since the original value will be exported. + } + + return null; + } + + internal object GetDisplayValue( object fieldValue ) + { + if( fieldValue == null ) + return null; + + var foreignKeyConverter = this.ForeignKeyConverter; + if( foreignKeyConverter != null ) + return foreignKeyConverter.GetValueFromKey( fieldValue, this ); + + return fieldValue; + } } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(ForeignKeys)/DataTableForeignKeyDescription.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(ForeignKeys)/DataTableForeignKeyDescription.cs index d765727b..816d0cd3 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(ForeignKeys)/DataTableForeignKeyDescription.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/(ForeignKeys)/DataTableForeignKeyDescription.cs @@ -21,11 +21,8 @@ namespace Xceed.Wpf.DataGrid { public class DataTableForeignKeyDescription : DataGridForeignKeyDescription { - #region CONSTRUCTORS - public DataTableForeignKeyDescription() { - this.ForeignKeyConverter = new DataTableForeignKeyConverter(); } internal DataTableForeignKeyDescription( ForeignKeyConstraint constraint ) @@ -34,8 +31,6 @@ namespace Xceed.Wpf.DataGrid this.ForeignKeyConstraint = constraint; } - #endregion - #region ForeignKeyConstraint Property public static readonly DependencyProperty ForeignKeyConstraintProperty = DependencyProperty.Register( @@ -70,7 +65,10 @@ namespace Xceed.Wpf.DataGrid #endregion - #region PRIVATE METHODS + protected override void SetForeignKeyConverter() + { + this.ForeignKeyConverter = new DataTableForeignKeyConverter(); + } private void UpdateValuePath() { @@ -111,7 +109,5 @@ namespace Xceed.Wpf.DataGrid this.ItemsSource = relatedTable.DefaultView; } - - #endregion } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/AsyncQueryInfo.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/AsyncQueryInfo.cs index db3b3f9e..e06f09cf 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/AsyncQueryInfo.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/AsyncQueryInfo.cs @@ -15,19 +15,14 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Threading; -using System.Diagnostics; using System.Collections.Specialized; +using System.Diagnostics; +using System.Windows.Threading; namespace Xceed.Wpf.DataGrid { public class AsyncQueryInfo : IDisposable { - #region CONSTRUCTORS - internal AsyncQueryInfo( Dispatcher dispatcher, Action beginQueryDelegate, @@ -50,34 +45,6 @@ namespace Xceed.Wpf.DataGrid m_requestedItemCount = requestedItemCount; } - #endregion CONSTRUCTORS - - #region BeginQueryDelegateInvoked Private Property - - private bool BeginQueryDelegateInvoked - { - get - { - return m_flags[ ( int )AsyncQueryInfoFlags.BeginQueryDelegateInvoked ]; - } - set - { - m_flags[ ( int )AsyncQueryInfoFlags.BeginQueryDelegateInvoked ] = value; - } - } - - #endregion - - #region EndQueryDelegateDispatcherOperation Private Property - - private DispatcherOperation EndQueryDelegateDispatcherOperation - { - get; - set; - } - - #endregion - #region StartIndex Property public int StartIndex @@ -88,7 +55,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion StartIndex Property + #endregion #region RequestedItemCount Property @@ -100,23 +67,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion RequestedItemCount Property - - #region ShouldAbort Property - - public bool ShouldAbort - { - get - { - return m_flags[ ( int )AsyncQueryInfoFlags.ShouldAbort ]; - } - private set - { - m_flags[ ( int )AsyncQueryInfoFlags.ShouldAbort ] = value; - } - } - - #endregion ShouldAbort Property + #endregion #region AsyncState Property @@ -126,7 +77,7 @@ namespace Xceed.Wpf.DataGrid set; } - #endregion AsyncState Property + #endregion #region Error Property @@ -146,18 +97,31 @@ namespace Xceed.Wpf.DataGrid if( m_queryErrorChangedDelegate != null ) { - m_dispatcher.Invoke( - DispatcherPriority.Send, - m_queryErrorChangedDelegate, - this ); + m_dispatcher.Invoke( DispatcherPriority.Send, m_queryErrorChangedDelegate, this ); } } } } - #endregion Error Property + #endregion + + #region ShouldAbort Property + + public bool ShouldAbort + { + get + { + return m_flags[ ( int )AsyncQueryInfoFlags.ShouldAbort ]; + } + private set + { + m_flags[ ( int )AsyncQueryInfoFlags.ShouldAbort ] = value; + } + } + + #endregion - #region IsDisposed Internal Property + #region IsDisposed Property internal bool IsDisposed { @@ -173,7 +137,21 @@ namespace Xceed.Wpf.DataGrid #endregion - #region PUBLIC METHODS + #region BeginQueryDelegateInvoked Property + + private bool BeginQueryDelegateInvoked + { + get + { + return m_flags[ ( int )AsyncQueryInfoFlags.BeginQueryDelegateInvoked ]; + } + set + { + m_flags[ ( int )AsyncQueryInfoFlags.BeginQueryDelegateInvoked ] = value; + } + } + + #endregion public void EndQuery( object[] items ) { @@ -181,21 +159,15 @@ namespace Xceed.Wpf.DataGrid if( this.IsDisposed ) return; - if( this.EndQueryDelegateDispatcherOperation != null ) + if( m_endQueryDelegateDispatcherOperation != null ) throw new InvalidOperationException( "An attempt was made to call EndQuery when it has already been called for this AsyncQueryInfo." ); if( this.ShouldAbort ) return; - this.EndQueryDelegateDispatcherOperation = - m_dispatcher.BeginInvoke( DispatcherPriority.Background, m_endQueryDelegate, - this, new object[] { items } ); + m_endQueryDelegateDispatcherOperation = m_dispatcher.BeginInvoke( DispatcherPriority.Background, m_endQueryDelegate, this, new object[] { items } ); } - #endregion PUBLIC METHODS - - #region INTERNAL METHODS - internal void QueueQuery() { Debug.Assert( !this.IsDisposed, "The AsyncQueryInfo is disposed" ); @@ -203,71 +175,51 @@ namespace Xceed.Wpf.DataGrid this.ShouldAbort = false; this.BeginQueryDelegateInvoked = false; - var endQueryDelegateOperation = this.EndQueryDelegateDispatcherOperation; - if( endQueryDelegateOperation != null ) + //Make sure to abort the EndQuery operation before queuing a new query. + if( m_endQueryDelegateDispatcherOperation != null ) { - this.EndQueryDelegateDispatcherOperation.Abort(); - this.EndQueryDelegateDispatcherOperation = null; + m_endQueryDelegateDispatcherOperation.Abort(); + m_endQueryDelegateDispatcherOperation = null; } #if SILVERLIGHT m_dispatcher.BeginInvoke( new Action( this.BeginQuery ) ); #else - m_beginQueryDispatcherOperation = m_dispatcher.BeginInvoke( DispatcherPriority.Background, - new Action( this.BeginQueryDispatcherCallback ) ); + m_beginQueryDispatcherOperation = m_dispatcher.BeginInvoke( DispatcherPriority.Background, new Action( this.BeginQueryDispatcherCallback ) ); #endif } - private void BeginQueryDispatcherCallback() - { - m_beginQueryDispatcherOperation = null; - - Debug.Assert( !this.IsDisposed ); - - if( this.ShouldAbort ) - { - Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "BUILT-IN BeginQueryDispatcherCallback Aborted! (" + this.GetHashCode() + ") For page at starting index: " + m_startIndex.ToString() ); - m_builtInAbortDelegate( this ); - return; - } - - m_beginQueryDelegate( this ); - this.BeginQueryDelegateInvoked = true; - } - internal void AbortQuery() { Debug.Assert( !this.IsDisposed ); - // Already dispatcher on the UI Thread the method that will fill the page. - // If it did have one, we would have invoked instead of BeginInvoked the endQuery delegate. - var endQueryDelegateOperation = this.EndQueryDelegateDispatcherOperation; - if( endQueryDelegateOperation != null ) + // Make sure to abort the EndQuery operation before queuing an abort query. + if( m_endQueryDelegateDispatcherOperation != null ) { - this.EndQueryDelegateDispatcherOperation.Abort(); - this.EndQueryDelegateDispatcherOperation = null; + m_endQueryDelegateDispatcherOperation.Abort(); + m_endQueryDelegateDispatcherOperation = null; } if( this.ShouldAbort ) { Debug.Assert( m_beginQueryDispatcherOperation == null ); + m_builtInAbortDelegate( this ); return; } this.ShouldAbort = true; - // If the BeginQuery already had time to execute, then we know the user was notified of the query request. - // Notify him to cancel the query as soon as possible. + // If the BeginQuery already had time to execute, then we know the user was notified of the query request. Notify him to cancel the query as soon as possible. if( this.BeginQueryDelegateInvoked ) { Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "CALLING Abort Query! For page at starting index: " + m_startIndex.ToString() ); + m_dispatcher.BeginInvoke( DispatcherPriority.Send, m_abortQueryDelegate, this ); } else { - // BeginQueryDispatcherCallback was dispatched - // but not executed yet, abort it and return + // BeginQueryDispatcherCallback was dispatched but not executed yet, abort it and return if( m_beginQueryDispatcherOperation != null ) { m_beginQueryDispatcherOperation.Abort(); @@ -278,9 +230,43 @@ namespace Xceed.Wpf.DataGrid } } - #endregion INTERNAL METHODS + private void BeginQueryDispatcherCallback() + { + m_beginQueryDispatcherOperation = null; + + Debug.Assert( !this.IsDisposed ); + + if( this.ShouldAbort ) + { + Debug.WriteLineIf( VirtualPageManager.DebugDataVirtualization, "BUILT-IN BeginQueryDispatcherCallback Aborted! (" + this.GetHashCode() + ") For page at starting index: " + m_startIndex.ToString() ); + + m_builtInAbortDelegate( this ); + return; + } + + m_beginQueryDelegate( this ); + this.BeginQueryDelegateInvoked = true; + } - #region PRIVATE FIELDS + #region IDisposable Members + + public void Dispose() + { + m_dispatcher = null; + + Debug.Assert( m_beginQueryDispatcherOperation == null, "A BeginQueryDispatcherCallback is still pending on the Dispatcher" ); + + m_beginQueryDispatcherOperation = null; + m_builtInAbortDelegate = null; + m_abortQueryDelegate = null; + m_beginQueryDelegate = null; + m_endQueryDelegate = null; + m_queryErrorChangedDelegate = null; + + this.IsDisposed = true; + } + + #endregion private int m_startIndex; private int m_requestedItemCount; @@ -292,16 +278,13 @@ namespace Xceed.Wpf.DataGrid private Dispatcher m_dispatcher; private DispatcherOperation m_beginQueryDispatcherOperation; + private DispatcherOperation m_endQueryDelegateDispatcherOperation; private Action m_builtInAbortDelegate; private Action m_beginQueryDelegate; private Action m_abortQueryDelegate; private Action m_endQueryDelegate; private Action m_queryErrorChangedDelegate; - #endregion PRIVATE FIELDS - - #region AsyncQueryInfoFlags Private Enum - [Flags] private enum AsyncQueryInfoFlags { @@ -310,27 +293,5 @@ namespace Xceed.Wpf.DataGrid BeginQueryDelegateInvoked = 4, IsDisposed = 8, } - - #endregion - - #region IDisposable Members - - public void Dispose() - { - m_dispatcher = null; - - Debug.Assert( m_beginQueryDispatcherOperation == null, "A BeginQueryDispatcherCallback is still pending on the Dispatcher" ); - - m_beginQueryDispatcherOperation = null; - m_builtInAbortDelegate = null; - m_abortQueryDelegate = null; - m_beginQueryDelegate = null; - m_endQueryDelegate = null; - m_queryErrorChangedDelegate = null; - - this.IsDisposed = true; - } - - #endregion } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/AutoFilterValuesChangedEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/AutoFilterValuesChangedEventArgs.cs deleted file mode 100644 index 259b4e41..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/AutoFilterValuesChangedEventArgs.cs +++ /dev/null @@ -1,74 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Collections.Specialized; -using System.Collections.ObjectModel; -using System.Collections; - -namespace Xceed.Wpf.DataGrid -{ - internal class AutoFilterValuesChangedEventArgs : EventArgs - { - internal AutoFilterValuesChangedEventArgs( - DataGridDetailDescription detailDescription, - DataGridItemPropertyBase itemProperty, - IList autoFilterValues, - NotifyCollectionChangedEventArgs collectionChangedEvent ) - { - if( itemProperty == null ) - throw new ArgumentNullException( "itemProperty" ); - - if( autoFilterValues == null ) - throw new ArgumentNullException( "autoFilterValues" ); - - if( collectionChangedEvent == null ) - throw new ArgumentNullException( "collectionChangedEvent" ); - - this.DetailDescription = detailDescription; - this.ItemProperty = itemProperty; - this.CollectionChangedEventArgs = collectionChangedEvent; - this.AutoFilterValues = autoFilterValues; - } - - internal DataGridDetailDescription DetailDescription - { - get; - private set; - } - - public DataGridItemPropertyBase ItemProperty - { - get; - private set; - } - - public NotifyCollectionChangedEventArgs CollectionChangedEventArgs - { - get; - private set; - } - - public ICollection AutoFilterValues - { - get; - private set; - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/CollectionViewGroupExtensions.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/CollectionViewGroupExtensions.cs index 7bca758d..0b56e991 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/CollectionViewGroupExtensions.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/CollectionViewGroupExtensions.cs @@ -46,7 +46,7 @@ namespace Xceed.Wpf.DataGrid startIndex = dataGridCollectionViewGroup.GetFirstRawItemGlobalSortedIndex(); endIndex = startIndex + dataGridCollectionViewGroup.GlobalRawItemCount - 1; } - else if(collectionViewGroup.ItemCount > 0) + else if( collectionViewGroup.ItemCount > 0 ) { if( dataGridContext == null ) throw new DataGridInternalException( "This collectionViewGroup require a DataGridContext instance" ); @@ -61,8 +61,8 @@ namespace Xceed.Wpf.DataGrid } } - return (startIndex >= 0 ) && (startIndex <= endIndex) - ? new SelectionRange(startIndex, endIndex) + return ( startIndex >= 0 ) && ( startIndex <= endIndex ) + ? new SelectionRange( startIndex, endIndex ) : SelectionRange.Empty; } @@ -96,7 +96,7 @@ namespace Xceed.Wpf.DataGrid { if( item is CollectionViewGroup ) { - foreach(var subItem in ( ( CollectionViewGroup )item ).GetLeafItems()) + foreach( var subItem in ( ( CollectionViewGroup )item ).GetLeafItems() ) { yield return subItem; } @@ -141,7 +141,6 @@ namespace Xceed.Wpf.DataGrid internal static IEnumerable GetSubGroups( this CollectionViewGroup collectionViewGroup ) { - foreach( var item in collectionViewGroup.GetItems() ) { var subGroup = item as CollectionViewGroup; diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/CustomDistinctValueItemConfiguration.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/CustomDistinctValueItemConfiguration.cs index 7c4ccd74..97e9ce23 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/CustomDistinctValueItemConfiguration.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/CustomDistinctValueItemConfiguration.cs @@ -33,39 +33,5 @@ namespace Xceed.Wpf.DataGrid get; set; } - - public event EventHandler Filter - { - add - { - EventHandler eventHandler = m_filter; - - if( eventHandler != null ) - { - throw new DataGridException( "A Filter event is already registered for this custom distinct value configuration." ); - } - else - { - m_filter = value; - } - } - remove - { - // The event handler was not registered on this configuration, ignore it - if( ( value != null ) && ( value != m_filter ) ) - return; - - if( m_filter != null ) - EventHandler.Remove( m_filter, value ); - } - } - - private event EventHandler m_filter; - - internal void RaiseCustomDistinctValueItemSelectedEvent( CustomDistinctValueItemFilterEventArgs args ) - { - if( m_filter != null ) - m_filter( this, args ); - } } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionView.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionView.cs index 642346d9..f09e6d94 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionView.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionView.cs @@ -27,7 +27,6 @@ using System.Threading; using System.Windows.Data; using Xceed.Utils.Collections; using Xceed.Utils.Data; -using Xceed.Wpf.DataGrid.Stats; namespace Xceed.Wpf.DataGrid { @@ -72,8 +71,6 @@ namespace Xceed.Wpf.DataGrid if( collection == null ) throw new ArgumentNullException( "collection" ); - this.UpdateChangedPropertyStatsOnly = parentDataGridCollectionView.UpdateChangedPropertyStatsOnly; - //If already deferring refreshes while a detail grid is expanded. if( parentDataGridCollectionView.InDeferRefresh ) { @@ -108,54 +105,6 @@ namespace Xceed.Wpf.DataGrid this.RootGroup = new DataGridCollectionViewGroupRoot( this ); } - #region StatFunctions Property - - internal StatFunctionCollection StatFunctions - { - get - { - return m_statFunctions; - } - } - - private StatFunctionCollection m_statFunctions; // = null - - #endregion StatFunctions Property - - #region InvalidatedStatFunctions Property - - internal ICollection InvalidatedStatFunctions - { - get - { - return m_invalidatedStatFunctions; - } - } - - private HashSet m_invalidatedStatFunctions = new HashSet(); - - #endregion - - #region UpdateChangedPropertyStatsOnly Property - - internal bool UpdateChangedPropertyStatsOnly - { - get; - set; - } - - #endregion - - #region CalculateChangedPropertyStatsOnly Property - - internal bool CalculateChangedPropertyStatsOnly - { - get; - set; - } - - #endregion - #region SourceItems Property public IList SourceItems @@ -280,18 +229,6 @@ namespace Xceed.Wpf.DataGrid #endregion - #region CanHaveDetails Property - - internal override bool CanHaveDetails - { - get - { - return true; - } - } - - #endregion - #region SortedItemVersion Property internal int SortedItemVersion @@ -338,20 +275,6 @@ namespace Xceed.Wpf.DataGrid #endregion - #region RootGroupChanged Internal Event - - internal event EventHandler RootGroupChanged; - - private void OnRootGroupChanged( EventArgs e ) - { - if( this.RootGroupChanged != null ) - { - this.RootGroupChanged( this, e ); - } - } - - #endregion RootGroupChanged Internal Event - public override bool MoveCurrentToPosition( int position ) { if( position == this.CurrentPosition ) @@ -392,10 +315,7 @@ namespace Xceed.Wpf.DataGrid if( ( !this.IsSourceSupportingChangeNotification ) && ( sourceIndex != -1 ) ) { - DeferredOperation deferredOperation = new DeferredOperation( - DeferredOperation.DeferredOperationAction.Remove, - sourceIndex, - new object[] { dataItem } ); + DeferredOperation deferredOperation = new DeferredOperation( DeferredOperation.DeferredOperationAction.Remove, sourceIndex, new object[] { dataItem } ); this.ExecuteOrQueueSourceItemOperation( deferredOperation ); } @@ -423,11 +343,6 @@ namespace Xceed.Wpf.DataGrid this.ExecuteOrQueueSourceItemOperation( deferredOperation ); } - public void RefreshDistinctValuesForFieldName( string fieldName ) - { - this.ForceRefreshDistinctValuesForFieldName( fieldName ); - } - public void RefreshUnboundItemProperties( object item = null ) { DeferredOperation deferredOperation = new DeferredOperation( DeferredOperation.DeferredOperationAction.RefreshUnboundItemProperties, item ); @@ -456,70 +371,6 @@ namespace Xceed.Wpf.DataGrid internal override void CreateDefaultCollections( DataGridDetailDescription parentDetailDescription ) { base.CreateDefaultCollections( parentDetailDescription ); - - m_statFunctions = ( parentDetailDescription != null ) ? parentDetailDescription.StatFunctions : new StatFunctionCollection(); - } - - internal override void RefreshDistinctValuesForField( DataGridItemPropertyBase dataGridItemProperty ) - { - if( dataGridItemProperty == null ) - return; - - if( !dataGridItemProperty.CalculateDistinctValues ) - return; - - // List containing current column distinct values, we pass the DistinctvaluesEqualityComparer if any. Null will force the HashTable to use the default one - HashSet currentColumnDistinctValues = new HashSet( new EqualityComparerWrapper( dataGridItemProperty.DistinctValuesEqualityComparer ) ); - - ReadOnlyObservableHashList readOnlyColumnDistinctValues = null; - - // If the key is not set in DistinctValues yet, do not calculate distinct values for this field - if( !( ( DistinctValuesDictionary )this.DistinctValues ).InternalTryGetValue( dataGridItemProperty.Name, out readOnlyColumnDistinctValues ) ) - return; - - ObservableHashList columnDistinctValues = readOnlyColumnDistinctValues.InnerObservableHashList; - - // We use the DistinctValuesSortComparer if present, else the SortComparer for the DataGridItemProperty, else, the Comparer used is the one of the base class. - IComparer distinctValuesSortComparer = dataGridItemProperty.DistinctValuesSortComparer; - - using( columnDistinctValues.DeferINotifyCollectionChanged() ) - { - // If none was specified, we use the default SortComparer for the DataGridItemProperty - if( distinctValuesSortComparer == null ) - { - distinctValuesSortComparer = dataGridItemProperty.SortComparer; - } - - List currentItemsList = this.GetItemsList(); - int rowsCount = currentItemsList.Count; // Parse every rows to get distinct values - int maximumDistinctValuesCount = dataGridItemProperty.MaxDistinctValues; - - for( int rowIndex = 0; rowIndex < rowsCount; rowIndex++ ) - { - object rowItem = currentItemsList[ rowIndex ].DataItem; - - // If we have more than one filtered item : - // we need to verify if the row passes every AUTO filter except the filtered one to get - if( this.DistinctValuesConstraint == DistinctValuesConstraint.Filtered ) - { - if( !this.PassesAutoFilter( rowItem, dataGridItemProperty ) ) - continue; - } - - object distinctValue = dataGridItemProperty.GetValue( rowItem ); - - // Allow the user to provide the corresponding distinct value for this item - distinctValue = dataGridItemProperty.GetDistinctValueFromItem( distinctValue ); - - // Compute current value to be able to remove unused values Accept if -1 => no maximum, or less than maximum specified - if( ( maximumDistinctValuesCount == -1 ) || ( maximumDistinctValuesCount > currentColumnDistinctValues.Count ) ) - { - currentColumnDistinctValues.Add( distinctValue ); - } - } - - DataGridCollectionViewBase.RemoveUnusedDistinctValues( distinctValuesSortComparer, currentColumnDistinctValues, columnDistinctValues, null ); - } } internal override bool CanCreateItemProperties() @@ -530,22 +381,31 @@ namespace Xceed.Wpf.DataGrid return ( m_sourceItems.Count != 0 ); } - internal override bool CanCreateDetailDescriptions() - { - if( base.CanCreateDetailDescriptions() ) - return true; - - return ( m_sourceItems.Count != 0 ); - } - internal override int IndexOfSourceItem( object item ) { if( item != null ) { - RawItem rawItem = this.GetFirstRawItemFromDataItem( item ); - if( rawItem != null ) + // The source index of raw items may not be up-to-date if some operations were deferred. + if( !this.DeferredOperationManager.HasPendingOperations ) { - return rawItem.Index; + // Use the RawItem/DataItem mapping instead of looping through the list for efficency. + var rawItem = this.GetFirstRawItemFromDataItem( item ); + + if( rawItem != null ) + return rawItem.Index; + } + + IList list = this.Enumeration as IList; + if( list != null ) + return list.IndexOf( item ); + + var index = 0; + foreach( var obj in this.Enumeration ) + { + if( obj == item ) + return index; + + index++; } } @@ -586,15 +446,6 @@ namespace Xceed.Wpf.DataGrid case DeferredOperation.DeferredOperationAction.RefreshDistincValues: { refreshForced = false; - if( this.DistinctValuesUpdateMode == DistinctValuesUpdateMode.Manual ) - { - //Let the AutoFilterControl (or the user) decide when to refresh DistinctValues. - this.RaiseDistinctValuesRefreshNeeded(); - } - else - { - this.ForceRefreshDistinctValues( deferredOperation.FilteredItemsChanged ); - } break; } @@ -605,11 +456,13 @@ namespace Xceed.Wpf.DataGrid // Ensure to defer the CurrentItem change when regrouping is completed to be sure the SaveCurrent has the right values when restoring using( this.DeferCurrencyEvent() ) { - int oldCurrentPosition = -1; - RawItem oldCurrentRawItem = null; + var oldCurrentPosition = -1; + var oldCurrentRawItem = default( RawItem ); + this.SaveCurrentBeforeReset( out oldCurrentRawItem, out oldCurrentPosition ); - SortDescriptionInfo[] sortDescriptionInfos; + var sortDescriptionInfos = default( IList ); + this.GroupItems(); this.PrepareSort( out sortDescriptionInfos ); this.SortItems( sortDescriptionInfos ); @@ -641,11 +494,13 @@ namespace Xceed.Wpf.DataGrid // Ensure to defer the CurrentItem change when resort is completed to be sure the SaveCurrent has the right values when restoring using( this.DeferCurrencyEvent() ) { - int oldCurrentPosition = -1; - RawItem oldCurrentRawItem = null; + var oldCurrentPosition = -1; + var oldCurrentRawItem = default( RawItem ); + this.SaveCurrentBeforeReset( out oldCurrentRawItem, out oldCurrentPosition ); - SortDescriptionInfo[] sortDescriptionInfos; + var sortDescriptionInfos = default( IList ); + this.PrepareSort( out sortDescriptionInfos ); this.SortItems( sortDescriptionInfos ); @@ -699,50 +554,6 @@ namespace Xceed.Wpf.DataGrid } } - internal override void ProcessInvalidatedGroupStats( HashSet invalidatedGroups ) - { - foreach( DataGridCollectionViewGroup group in invalidatedGroups ) - { - group.InvokeStatFunctionsPropertyChanged( this ); - } - - if( m_hasGroupSortBasedOnStats ) - { - using( this.DeferCurrencyEvent() ) - { - object oldCurrentDataItem = this.CurrentItem; - int oldCurrentPosition = this.CurrentPosition; - - this.SortGroups(); - - RawItem currentRawItem = null; - - if( oldCurrentDataItem != null ) - { - currentRawItem = this.GetFirstRawItemFromDataItem( oldCurrentDataItem ); - } - - if( currentRawItem == null ) - { - if( ( oldCurrentPosition > 0 ) && ( oldCurrentPosition < this.RootGroup.GlobalRawItemCount ) ) - { - currentRawItem = this.RootGroup.GetRawItemAtGlobalSortedIndex( oldCurrentPosition ); - } - } - - if( currentRawItem != null ) - { - this.SetCurrentItem( currentRawItem.GetGlobalSortedIndex(), oldCurrentDataItem, false, false ); - } - - this.OnCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Reset ) ); - } - } - - this.CalculateChangedPropertyStatsOnly = false; - this.InvalidatedStatFunctions.Clear(); - } - internal override void ForceRefresh( bool sendResetNotification, bool initialLoad, bool setCurrentToFirstOnInitialLoad ) { if( this.Refreshing ) @@ -752,18 +563,16 @@ namespace Xceed.Wpf.DataGrid throw new InvalidOperationException( "An attempt was made to refresh the DataGridCollectionView while it is already in the process of refreshing distinct values." ); this.SetCurrentEditItem( null ); - int oldCurrentPosition = -1; - RawItem oldCurrentRawItem = null; - // The cache of PropertyDescriptors for the StatFunctions will be recreated if needed in GetStatFunctionProperties(). - m_statisticalProperties = null; + var oldCurrentPosition = -1; + var oldCurrentRawItem = default( RawItem ); if( !initialLoad ) { this.SaveCurrentBeforeReset( out oldCurrentRawItem, out oldCurrentPosition ); } - SortDescriptionInfo[] sortDescriptionInfos = null; + var sortDescriptionInfos = default( IList ); using( this.DeferCurrencyEvent() ) { @@ -773,20 +582,20 @@ namespace Xceed.Wpf.DataGrid { lock( this.SyncRoot ) { - DeferredOperationManager deferredOperationManager = this.DeferredOperationManager; + var deferredOperationManager = this.DeferredOperationManager; lock( deferredOperationManager ) { deferredOperationManager.ClearDeferredOperations(); m_lastAddCount = -1; - bool bLoaded = false; - IEnumerable enumeration = this.Enumeration; - CollectionView collectionView = enumeration as CollectionView; + var bLoaded = false; + var enumeration = this.Enumeration; + var collectionView = enumeration as CollectionView; if( collectionView == null ) { - IList list = enumeration as IList; + var list = enumeration as IList; if( list != null ) { @@ -798,17 +607,12 @@ namespace Xceed.Wpf.DataGrid for( int i = 0; i < count; i++ ) { - object item = list[ i ]; - RawItem rawItem = new RawItem( i, item ); + var item = list[ i ]; + var rawItem = new RawItem( i, item ); + m_sourceItemList.Add( rawItem ); this.AddRawItemDataItemMapping( rawItem ); - - if( this.PassesFilter( item ) - && this.PassesAutoFilter( item, null ) - && this.PassesFilterCriterion( rawItem.DataItem ) ) - { - m_filteredItemList.Add( rawItem ); - } + m_filteredItemList.Add( rawItem ); } bLoaded = true; @@ -819,7 +623,7 @@ namespace Xceed.Wpf.DataGrid { if( enumeration != null ) { - int count = 128; + var count = 128; if( collectionView != null ) { @@ -827,8 +631,7 @@ namespace Xceed.Wpf.DataGrid } else { - ICollection collection = enumeration as ICollection; - + var collection = enumeration as ICollection; if( collection != null ) { count = collection.Count; @@ -839,23 +642,19 @@ namespace Xceed.Wpf.DataGrid m_filteredItemList.Clear(); m_dataItemToRawItemMap.Clear(); - int index = 0; - IEnumerator enumerator = enumeration.GetEnumerator(); + var index = 0; + var enumerator = enumeration.GetEnumerator(); while( enumerator.MoveNext() ) { - object item = enumerator.Current; - RawItem rawItem = new RawItem( index, item ); + var item = enumerator.Current; + var rawItem = new RawItem( index, item ); + index++; m_sourceItemList.Add( rawItem ); - this.AddRawItemDataItemMapping( rawItem ); - if( this.PassesFilter( item ) - && this.PassesAutoFilter( item, null ) - && this.PassesFilterCriterion( rawItem.DataItem ) ) - { - m_filteredItemList.Add( rawItem ); - } + this.AddRawItemDataItemMapping( rawItem ); + m_filteredItemList.Add( rawItem ); } } } @@ -872,16 +671,6 @@ namespace Xceed.Wpf.DataGrid } } - if( this.DistinctValuesUpdateMode == DistinctValuesUpdateMode.Manual ) - { - //Let the AutoFilterControl (or the user) decide when to refresh DistinctValues. - this.RaiseDistinctValuesRefreshNeeded(); - } - else - { - this.ForceRefreshDistinctValues( true ); - } - this.SortItems( sortDescriptionInfos ); unchecked @@ -916,6 +705,7 @@ namespace Xceed.Wpf.DataGrid internal override void ClearGroupSortComparers() { m_groupSortComparers.Clear(); + m_groupSortComparers.TrimExcess(); } internal RawItem GetRawItemAt( int index ) @@ -937,21 +727,6 @@ namespace Xceed.Wpf.DataGrid return m_sourceItemList.GetEnumerator(); } - internal PropertyDescriptorCollection GetStatFunctionProperties() - { - if( m_statisticalProperties == null ) - { - m_statisticalProperties = new PropertyDescriptorCollection( null ); - - foreach( StatFunction statFunction in m_statFunctions ) - { - m_statisticalProperties.Add( new StatFunctionPropertyDescriptor( statFunction.ResultPropertyName ) ); - } - } - - return m_statisticalProperties; - } - internal bool AddSourceItem( int startIndex, IList items, int newSourceItemCount ) { if( items == null ) @@ -973,29 +748,17 @@ namespace Xceed.Wpf.DataGrid m_lastAddCount = newSourceItemCount; m_lastAddIndex = startIndex; - var filteredItemsChanged = false; - for( int i = 0; i < items.Count; i++ ) { var index = startIndex + i; var item = items[ i ]; var rawItem = new RawItem( index, item ); - if( this.PassesFilter( item ) && this.PassesAutoFilter( item, null ) && this.PassesFilterCriterion( item ) ) - { - filteredItemsChanged = true; - - this.AddRawItemInSourceList( index, rawItem ); - this.AddRawItemInFilteredList( rawItem ); - this.AddRawItemInGroup( rawItem ); - } - else - { - this.AddRawItemInSourceList( index, rawItem ); - } + this.AddRawItemInSourceList( index, rawItem ); + this.AddRawItemInFilteredList( rawItem ); + this.AddRawItemInGroup( rawItem ); } - this.RefreshDistinctValues( filteredItemsChanged ); return true; } @@ -1009,8 +772,6 @@ namespace Xceed.Wpf.DataGrid return false; } - var filteredItemsChanged = false; - for( int i = 0; i < count; i++ ) { var rawItem = m_sourceItemList[ startIndex ]; @@ -1022,8 +783,6 @@ namespace Xceed.Wpf.DataGrid if( this.RemoveRawItemInFilteredList( rawItem ) ) { - filteredItemsChanged = true; - this.RemoveRawItemInSourceList( startIndex ); this.RemoveRawItemInGroup( rawItem ); } @@ -1033,7 +792,6 @@ namespace Xceed.Wpf.DataGrid } } - this.RefreshDistinctValues( filteredItemsChanged ); return true; } @@ -1070,14 +828,12 @@ namespace Xceed.Wpf.DataGrid RawItem rawItem = m_sourceItemList[ oldStartIndex + i ]; object oldItem = rawItem.DataItem; int globalSortedIndex = rawItem.GetGlobalSortedIndex(); + object newItem = newItems[ i ]; // globalSortedIndex == -1 means item does not pass filter if( globalSortedIndex != -1 ) { - object newItem = newItems[ i ]; - bool itemChanged = !object.Equals( oldItem, newItem ); - if( ( this.CurrentEditItem == oldItem ) && ( itemChanged ) ) { try @@ -1114,39 +870,20 @@ namespace Xceed.Wpf.DataGrid DataGridCollectionViewGroup newGroup = rawItem.ParentGroup; bool movedToDifferentParentGroup = oldGroup != newGroup; - - if( m_statFunctions.Count > 0 ) - { - DeferredOperationManager deferredOperationManager = this.DeferredOperationManager; - deferredOperationManager.InvalidateGroupStats( oldGroup, movedToDifferentParentGroup ); - if( movedToDifferentParentGroup ) - { - deferredOperationManager.InvalidateGroupStats( rawItem.ParentGroup, true ); - } - } } } else { - Debug.Assert( rawItem.ParentGroup == null, "ParentGroup should be null, since according to the comment at the top of the if, the item is filtered out" ); - - DataGridCollectionViewGroup oldGroup = rawItem.ParentGroup; - - // Since it is a replace, we must re-ensure position even if current item did not passed filter in case a property change would let it pass the filter - this.EnsurePosition( rawItem, globalSortedIndex ); - - DataGridCollectionViewGroup newGroup = rawItem.ParentGroup; - bool movedToDifferentParentGroup = oldGroup != newGroup; - - if( m_statFunctions.Count > 0 ) + if( newItem != oldItem ) { - DeferredOperationManager deferredOperationManager = this.DeferredOperationManager; - deferredOperationManager.InvalidateGroupStats( oldGroup, movedToDifferentParentGroup ); - if( movedToDifferentParentGroup ) - { - deferredOperationManager.InvalidateGroupStats( rawItem.ParentGroup, true ); - } + this.RemoveRawItemDataItemMapping( rawItem ); + rawItem.SetDataItem( newItem ); + this.AddRawItemDataItemMapping( rawItem ); } + + // Since it is a replace, we must re-ensure position and invalidate stats function (no need to invalidate the old group, since the old item is filtered + // out, and thus has no parent group), even if it is an item being replaced by itself, in case a property changed would now let it pass the filter. + this.EnsurePosition( rawItem, globalSortedIndex ); } } else @@ -1283,274 +1020,17 @@ namespace Xceed.Wpf.DataGrid } } - private List GetItemsList() - { - return ( this.DistinctValuesConstraint == DistinctValuesConstraint.FilteredWithAllFilters ) ? m_filteredItemList : m_sourceItemList; - } - private void EnsurePosition( RawItem rawItem, int globalSortedIndex ) { Debug.Assert( rawItem.GetGlobalSortedIndex() == globalSortedIndex ); var dataItem = rawItem.DataItem; - if( this.PassesFilter( dataItem ) && this.PassesAutoFilter( dataItem, null ) && this.PassesFilterCriterion( dataItem ) ) - { - if( globalSortedIndex == -1 ) - { - this.AddRawItemInFilteredList( rawItem ); - this.AddRawItemInGroup( rawItem ); - - this.RefreshDistinctValues( true ); - return; - } - else - { - this.RefreshDistinctValues( true ); - } - } - else - { - if( globalSortedIndex != -1 ) - { - this.RemoveRawItemInFilteredList( rawItem ); - this.RemoveRawItemInGroup( rawItem ); - } - - this.RefreshDistinctValues( true ); - return; - } - - // Verify the row is in the correct group. - var newGroup = this.GetRawItemNewGroup( rawItem ); - var currentGroup = rawItem.ParentGroup; - - if( currentGroup != newGroup ) - { - using( this.DeferCurrencyEvent() ) - { - if( m_statFunctions.Count > 0 ) - { - var deferredOperationManager = this.DeferredOperationManager; - - //If an item is moved from one group to another, make sure all stats for the specified groups are recalculated even if UpdateChangedPropertyStatsOnly is set to true - deferredOperationManager.InvalidateGroupStats( currentGroup, true ); - deferredOperationManager.InvalidateGroupStats( newGroup, true ); - } - - var newSortIndex = newGroup.BinarySearchRawItem( rawItem, this.RawItemSortComparer ); - - if( newSortIndex < 0 ) - { - newSortIndex = ~newSortIndex; - } - - currentGroup.RemoveRawItemAt( rawItem.SortedIndex ); - newGroup.InsertRawItem( newSortIndex, rawItem ); - var newGlobalSortedIndex = rawItem.GetGlobalSortedIndex(); - this.AdjustCurrencyAfterMove( globalSortedIndex, newGlobalSortedIndex, 1 ); - this.OnCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Move, rawItem.DataItem, newGlobalSortedIndex, globalSortedIndex ) ); - } - } - else - { - if( m_statFunctions.Count > 0 ) - { - this.DeferredOperationManager.InvalidateGroupStats( currentGroup ); - } - - // Verify sorting only if we have not changed group, since adding an item in a group will automatically sort it. - // Even if we are not sorted, we must ensure the order matches the natural order of the source. - int newSortIndex = newGroup.BinarySearchRawItem( rawItem, this.RawItemSortComparer ); - - if( newSortIndex < 0 ) - { - newSortIndex = ~newSortIndex; - } - - if( newSortIndex > rawItem.SortedIndex ) - { - newSortIndex--; - } - - if( rawItem.SortedIndex != newSortIndex ) - { - using( this.DeferCurrencyEvent() ) - { - newGroup.MoveRawItem( rawItem.SortedIndex, newSortIndex ); - var newGlobalSortedIndex = rawItem.GetGlobalSortedIndex(); - this.AdjustCurrencyAfterMove( globalSortedIndex, newGlobalSortedIndex, 1 ); - this.OnCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Move, rawItem.DataItem, newGlobalSortedIndex, globalSortedIndex ) ); - } - } - } - } - - // excludedFilteredDataGridItemProperty is used to avoid filtering the column on which we are calculating Distinct Values if null, this parameter is ignored - private bool PassesAutoFilter( object item, DataGridItemPropertyBase excludedFilteredDataGridItemProperty ) - { - AutoFilterMode autoFilterMode = this.AutoFilterMode; - - if( autoFilterMode == AutoFilterMode.None ) - return true; - - bool isRowAccepted = false; - bool isColumnFiltered = false; - - switch( autoFilterMode ) - { - case AutoFilterMode.And: - // Initially, we accept the row and reject on any filter difference - isRowAccepted = true; - break; - - case AutoFilterMode.Or: - // Initially, no criteria is met, we reject the row - isRowAccepted = false; - break; - } - - ObservableCollection autoFilteItems = this.AutoFilteredDataGridItemProperties; - int autoFilterItemsCount = autoFilteItems.Count; - - // The index of the last filtered item to calculate DistinctValuesConstraint.Filtered - int calculateDistinctValuesIndex = autoFilterItemsCount - 1; // Count for last item - - for( int propertyIndex = 0; propertyIndex < autoFilterItemsCount; propertyIndex++ ) - { - DataGridItemPropertyBase dataGridItemProperty = autoFilteItems[ propertyIndex ]; - - // If the excluded DataGridItemProperty is found - if( ( excludedFilteredDataGridItemProperty != null ) && ( dataGridItemProperty == excludedFilteredDataGridItemProperty ) ) - continue; - - // At least one column was filtered - isColumnFiltered = true; - - bool isCurrentFilterAccepted = false; - - // autoFilterValues will never be null - IList autoFilterValues = this.GetAutoFilterValues( dataGridItemProperty.Name ); - int filterCount = autoFilterValues.Count; - - if( filterCount > 0 ) - { - // Only get value if there are autoFilterValues for this dataGridItemProperty - object columnValue = dataGridItemProperty.GetValue( item ); - - // Allow the user to provide the corresponding distinct value for this item - columnValue = dataGridItemProperty.GetDistinctValueFromItem( columnValue ); - - // Check if one of the items in filter list passes - for( int filterIndex = 0; filterIndex < filterCount; filterIndex++ ) - { - object autoFilterValue = autoFilterValues[ filterIndex ]; - - // Use the DistinctValuesEqualityComparer for this DataGridItemProperty if specified - IEqualityComparer distinctValuesEqualityComparer = dataGridItemProperty.DistinctValuesEqualityComparer; - - if( distinctValuesEqualityComparer != null ) - { - if( distinctValuesEqualityComparer.Equals( autoFilterValue, columnValue ) ) - { - // Current column correspond to Filter value - isCurrentFilterAccepted = true; - break; - } - } - else if( ItemsSourceHelper.IsEntityFramework( autoFilterValue ) && ItemsSourceHelper.IsEntityFramework( columnValue ) ) - { - if( ( autoFilterValue is IComparable ) && ( columnValue is IComparable ) ) - { - IComparable autoFilterValueComparable = ( IComparable )autoFilterValue; - IComparable columnValueComparable = ( IComparable )columnValue; - - if( autoFilterValueComparable.CompareTo( columnValueComparable ) == 0 ) - { - isCurrentFilterAccepted = true; - break; - } - } - else - { - if( Object.Equals( autoFilterValue, columnValue ) ) - { - isCurrentFilterAccepted = true; - break; - } - } - } - else if( ObjectDataStore.CompareData( autoFilterValue, columnValue ) == 0 ) - { - // Current column correspond to Filter value - isCurrentFilterAccepted = true; - break; - } - } - } - - if( isCurrentFilterAccepted ) - { - isRowAccepted = true; - - // In FilteringMode.Or, accept the row right away, do not process other columns - if( autoFilterMode == AutoFilterMode.Or ) - break; - } - else - { - // One filtered column doesn't correspond to Filter value - if( autoFilterMode == AutoFilterMode.And ) - { - isRowAccepted = false; - break; - } - } - } - - // If no filter provided for any column, accept the row - if( !isColumnFiltered ) - isRowAccepted = true; - - return isRowAccepted; - } - - private bool PassesFilterCriterion( object item ) - { - FilterCriteriaMode filterMode = this.FilterCriteriaMode; - bool passesFilter = true; - - if( filterMode != FilterCriteriaMode.None ) + if( globalSortedIndex != -1 ) { - ReadOnlyCollection itemProperties = - this.FilteredCriterionItemProperties; - - int itemPropertyCount = itemProperties.Count; - - for( int i = 0; i < itemPropertyCount; i++ ) - { - DataGridItemPropertyBase itemProperty = itemProperties[ i ]; - Debug.Assert( itemProperty.FilterCriterion != null ); - - if( itemProperty.FilterCriterion == null ) - continue; - - passesFilter = itemProperty.FilterCriterion.IsMatch( itemProperty.GetValue( item ) ); - - if( filterMode == FilterCriteriaMode.And ) - { - if( !passesFilter ) - break; - } - else - { - if( passesFilter ) - break; - } - } + this.RemoveRawItemInFilteredList( rawItem ); + this.RemoveRawItemInGroup( rawItem ); } - - return passesFilter; } private bool SetCurrentItem( int newCurrentPosition, bool isCancelable ) @@ -1663,6 +1143,8 @@ namespace Xceed.Wpf.DataGrid return false; } + m_lastAddCount = -1; + if( oldStartIndex < newStartIndex ) { for( int i = count - 1; i >= 0; i-- ) @@ -1670,8 +1152,8 @@ namespace Xceed.Wpf.DataGrid var oldIndex = oldStartIndex + i; var newIndex = newStartIndex + i; - Debug.Assert( (oldIndex >= 0) && (oldIndex < m_sourceItemList.Count) ); - Debug.Assert( (newIndex >= 0) && (newIndex < m_sourceItemList.Count) ); + Debug.Assert( ( oldIndex >= 0 ) && ( oldIndex < m_sourceItemList.Count ) ); + Debug.Assert( ( newIndex >= 0 ) && ( newIndex < m_sourceItemList.Count ) ); var rawItem = m_sourceItemList[ oldIndex ]; var wasFiltered = this.RemoveRawItemInFilteredList( rawItem ); @@ -1698,8 +1180,8 @@ namespace Xceed.Wpf.DataGrid var oldIndex = oldStartIndex + i; var newIndex = newStartIndex + i; - Debug.Assert( (oldIndex >= 0) && (oldIndex < m_sourceItemList.Count) ); - Debug.Assert( (newIndex >= 0) && (newIndex < m_sourceItemList.Count) ); + Debug.Assert( ( oldIndex >= 0 ) && ( oldIndex < m_sourceItemList.Count ) ); + Debug.Assert( ( newIndex >= 0 ) && ( newIndex < m_sourceItemList.Count ) ); var rawItem = m_sourceItemList[ oldIndex ]; var wasFiltered = this.RemoveRawItemInFilteredList( rawItem ); @@ -1780,7 +1262,7 @@ namespace Xceed.Wpf.DataGrid private void AddRawItemInSourceList( int index, RawItem rawItem ) { - Debug.Assert( (index >= 0) && (index <= m_sourceItemList.Count) ); + Debug.Assert( ( index >= 0 ) && ( index <= m_sourceItemList.Count ) ); Debug.Assert( rawItem != null ); m_sourceItemList.Insert( index, rawItem ); @@ -1799,7 +1281,7 @@ namespace Xceed.Wpf.DataGrid // The function take for granted that all RawItem's index are sequential, // or if there is gap, the index contained in the gap are not already contained in the list. - if( (m_filteredItemList.Count == 0) || (m_filteredItemList.Last().Index < rawItem.Index) ) + if( ( m_filteredItemList.Count == 0 ) || ( m_filteredItemList.Last().Index < rawItem.Index ) ) { m_filteredItemList.Add( rawItem ); } @@ -1832,7 +1314,9 @@ namespace Xceed.Wpf.DataGrid } var globalIndex = newGroup.GetFirstRawItemGlobalSortedIndex() + index; + this.AdjustCurrencyBeforeAdd( globalIndex ); + newGroup.InsertRawItem( index, rawItem ); unchecked @@ -1842,17 +1326,11 @@ namespace Xceed.Wpf.DataGrid this.OnCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Add, rawItem.DataItem, globalIndex ) ); } - - //When adding an item, make sure all stats for the specified group are recalculated even if UpdateChangedPropertyStatsOnly is set to true - if( m_statFunctions.Count > 0 ) - { - this.DeferredOperationManager.InvalidateGroupStats( rawItem.ParentGroup, true ); - } } private void RemoveRawItemInSourceList( int index ) { - Debug.Assert( (index >= 0) && (index < m_sourceItemList.Count) ); + Debug.Assert( ( index >= 0 ) && ( index < m_sourceItemList.Count ) ); this.RemoveRawItemDataItemMapping( m_sourceItemList[ index ] ); @@ -1874,7 +1352,7 @@ namespace Xceed.Wpf.DataGrid if( index < 0 ) return false; - Debug.Assert( (index >= 0) && (index < m_filteredItemList.Count) ); + Debug.Assert( ( index >= 0 ) && ( index < m_filteredItemList.Count ) ); m_filteredItemList.RemoveAt( index ); @@ -1905,12 +1383,6 @@ namespace Xceed.Wpf.DataGrid // In the case of a remove, the CollectionChanged must be after the CurrentChanged since when the DataGridCollectionView is used with a Selector having the // IsSynchronizedWithCurrent set, the Selector will set the current position to -1 if the selected item is removed. this.OnCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Remove, rawItem.DataItem, globalSortedIndex ) ); - - //When removing an item, make sure all stats for the specified group are recalculated even if UpdateChangedPropertyStatsOnly is set to true - if( m_statFunctions.Count > 0 ) - { - this.DeferredOperationManager.InvalidateGroupStats( parentGroup, true ); - } } private bool RefreshUnboundItemPropertiesCore( object dataItem = null ) @@ -2056,13 +1528,12 @@ namespace Xceed.Wpf.DataGrid } } - private void SortItems( SortDescriptionInfo[] sortDescriptionInfos ) + private void SortItems( IList sortDescriptionInfos ) { // We set the current item to -1 to prevent the developper to get an invalid position. We will replace the current item to the correct one later. this.SetCurrentItem( -1, null, false, false ); - DataGridCollectionViewGroupRoot rootGroup = this.RootGroup; - + var rootGroup = this.RootGroup; if( rootGroup.IsBottomLevel ) { rootGroup.SortRootRawItems( sortDescriptionInfos, m_sourceItemList ); @@ -2070,7 +1541,7 @@ namespace Xceed.Wpf.DataGrid else { // We use a new DataGridCollectionViewGroupRoot to prevent some event to be raised. - DataGridCollectionViewGroupRoot newRootGroup = new DataGridCollectionViewGroupRoot( rootGroup ); + var newRootGroup = new DataGridCollectionViewGroupRoot( rootGroup ); rootGroup.SortItems( sortDescriptionInfos, this.GetGroupSortComparers(), 0, m_sourceItemList, newRootGroup ); @@ -2085,12 +1556,8 @@ namespace Xceed.Wpf.DataGrid private void SortGroups() { - DataGridCollectionViewGroupRoot rootGroup = this.RootGroup; - - if( rootGroup.IsBottomLevel ) - return; - - rootGroup.SortGroups( this.GetGroupSortComparers(), 0 ); + //This method assumes the that the RootGroup is not the bottom level group, i.e. there DataGrid is currently grouped. + this.RootGroup.SortGroups( this.GetGroupSortComparers(), 0 ); unchecked { @@ -2098,72 +1565,126 @@ namespace Xceed.Wpf.DataGrid } } - private void PrepareSort( out SortDescriptionInfo[] sortDescriptionInfos ) + private void ResortGroups() + { + using( this.DeferCurrencyEvent() ) + { + object oldCurrentDataItem = this.CurrentItem; + int oldCurrentPosition = this.CurrentPosition; + + this.SortGroups(); + + RawItem currentRawItem = null; + + if( oldCurrentDataItem != null ) + { + currentRawItem = this.GetFirstRawItemFromDataItem( oldCurrentDataItem ); + } + + if( currentRawItem == null ) + { + if( ( oldCurrentPosition > 0 ) && ( oldCurrentPosition < this.RootGroup.GlobalRawItemCount ) ) + { + currentRawItem = this.RootGroup.GetRawItemAtGlobalSortedIndex( oldCurrentPosition ); + } + } + + if( currentRawItem != null ) + { + this.SetCurrentItem( currentRawItem.GetGlobalSortedIndex(), oldCurrentDataItem, false, false ); + } + + this.OnCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Reset ) ); + } + } + + private void PrepareSort( out IList sortDescriptionInfos ) { - sortDescriptionInfos = null; + sortDescriptionInfos = new List(); lock( this.SyncRoot ) { lock( this.DeferredOperationManager ) { - SortDescriptionCollection sortDescriptions = this.SortDescriptions; - int sortDescriptionCount = sortDescriptions.Count; + var itemCount = m_sourceItemList.Count; - if( sortDescriptionCount > 0 ) + foreach( var sortDescription in this.SortDescriptions ) { - int itemCount = m_sourceItemList.Count; - sortDescriptionInfos = new SortDescriptionInfo[ sortDescriptionCount ]; - DataGridItemPropertyCollection itemProperties = this.ItemProperties; + var itemProperty = ItemsSourceHelper.GetItemPropertyFromProperty( this.ItemProperties, sortDescription.PropertyName ); + var sortDescriptionInfo = new SortDescriptionInfo( itemProperty, sortDescription.Direction ); - for( int i = 0; i < sortDescriptionCount; i++ ) - { - SortDescription sortDescription = sortDescriptions[ i ]; - DataGridItemPropertyBase dataProperty = itemProperties[ sortDescription.PropertyName ]; + sortDescriptionInfos.Add( sortDescriptionInfo ); - SortDescriptionInfo sortDescriptionInfo = new SortDescriptionInfo( dataProperty, sortDescription.Direction ); + if( itemProperty == null ) + continue; - sortDescriptionInfos[ i ] = sortDescriptionInfo; + // This will cache the data for the sorting + var dataStore = default( DataStore ); + var isSortingOnForeignKeyDescription = false; - if( dataProperty == null ) - continue; + var foreignKeyDescription = itemProperty.ForeignKeyDescription; + if( foreignKeyDescription != null ) + { + var dataType = foreignKeyDescription.GetDataType(); + if( dataType != null ) + { + dataStore = DataGridCollectionView.CreateStore( dataType, itemCount ); + isSortingOnForeignKeyDescription = true; + } + } - // This will cache the data for the sorting - DataStore dataStore; + itemProperty.IsSortingOnForeignKeyDescription = isSortingOnForeignKeyDescription; - if( dataProperty.SortComparer != null ) + //Create the DataStore if it has not been created yet. + if( !isSortingOnForeignKeyDescription ) + { + if( itemProperty.SortComparer != null ) { // If we have a sort comparer, keep the element in an object data type to increase the performance. dataStore = DataGridCollectionView.CreateStore( typeof( object ), itemCount ); } else { - dataStore = DataGridCollectionView.CreateStore( dataProperty.DataType, itemCount ); + dataStore = DataGridCollectionView.CreateStore( itemProperty.DataType, itemCount ); } + } - sortDescriptionInfo.DataStore = dataStore; - - ISupportInitialize supportInitialize = dataProperty as ISupportInitialize; + sortDescriptionInfo.DataStore = dataStore; - if( supportInitialize != null ) - { - supportInitialize.BeginInit(); - } + var supportInitialize = itemProperty as ISupportInitialize; + if( supportInitialize != null ) + { + supportInitialize.BeginInit(); + } - try + try + { + if( isSortingOnForeignKeyDescription ) { - for( int j = 0; j < itemCount; j++ ) + for( int i = 0; i < itemCount; i++ ) { - dataStore.SetData( j, dataProperty.GetValue( m_sourceItemList[ j ].DataItem ) ); + var value = ItemsSourceHelper.GetValueFromItemProperty( itemProperty, m_sourceItemList[ i ].DataItem ); + + dataStore.SetData( i, foreignKeyDescription.GetDisplayValue( value ) ); } } - finally + else { - if( supportInitialize != null ) + for( int i = 0; i < itemCount; i++ ) { - supportInitialize.EndInit(); + var value = ItemsSourceHelper.GetValueFromItemProperty( itemProperty, m_sourceItemList[ i ].DataItem ); + + dataStore.SetData( i, value ); } } } + finally + { + if( supportInitialize != null ) + { + supportInitialize.EndInit(); + } + } } } } @@ -2174,45 +1695,33 @@ namespace Xceed.Wpf.DataGrid if( m_groupSortComparers.Count > 0 ) return m_groupSortComparers; - m_hasGroupSortBasedOnStats = false; + var sortDescriptions = this.SortDescriptions; - SortDescriptionCollection sortDescriptions = this.SortDescriptions; - DataGridItemPropertyCollection itemProperties = this.ItemProperties; - - foreach( GroupDescription groupDescription in this.GroupDescriptions ) + foreach( var groupDescription in this.GroupDescriptions ) { - // Find the sortDescriptionInfo for the current sub group. - string groupDescriptionName = DataGridCollectionView.GetPropertyNameFromGroupDescription( groupDescription ); - List sortInfos = new List( sortDescriptions.Count ); + // Find all the SortInfos for the current sub group. + var groupDescriptionName = DataGridCollectionView.GetPropertyNameFromGroupDescription( groupDescription ); + var sortInfos = new List( sortDescriptions.Count + 1 ); - foreach( SortDescription sortDescription in sortDescriptions ) + foreach( var sortDescription in sortDescriptions ) { - ListSortDirection sortDirection = sortDescription.Direction; - string sortDescriptionName = sortDescription.PropertyName; - DataGridItemPropertyBase itemProperty = itemProperties[ sortDescriptionName ]; + var sortDirection = sortDescription.Direction; + var sortDescriptionName = sortDescription.PropertyName; + var itemProperty = ItemsSourceHelper.GetItemPropertyFromProperty( this.ItemProperties, sortDescriptionName ); - if( itemProperty != null ) + if( string.Equals( groupDescriptionName, sortDescriptionName ) ) { - string sortStatResultPropertyName = itemProperty.GroupSortStatResultPropertyName; - - if( !string.IsNullOrEmpty( sortStatResultPropertyName ) ) + var foreignKeyDescription = ( itemProperty != null ) ? itemProperty.ForeignKeyDescription : null; + if( foreignKeyDescription != null ) { - m_hasGroupSortBasedOnStats = true; - - IComparer sortComparer = itemProperty.GroupSortStatResultComparer; - - if( sortComparer == null ) + if( foreignKeyDescription.ItemsSource != null + && ( !string.IsNullOrWhiteSpace( foreignKeyDescription.DisplayMemberPath ) || ( foreignKeyDescription.ForeignKeyConverter != null ) ) ) { - sortComparer = StatResultComparer.Singleton; + sortInfos.Add( new GroupSortComparer.SortInfo( foreignKeyDescription, sortDirection, this.GetSortComparer( groupDescription, itemProperty ) ) ); } - - sortInfos.Add( new GroupSortComparer.SortInfo( sortStatResultPropertyName, sortDirection, sortComparer ) ); } - } - if( string.Equals( groupDescriptionName, sortDescriptionName ) ) - { - sortInfos.Add( this.CreateDefaultGroupSortInfo( groupDescription, itemProperty, sortDirection ) ); + sortInfos.Add( new GroupSortComparer.SortInfo( sortDirection, this.GetSortComparer( groupDescription, itemProperty ) ) ); } } @@ -2222,10 +1731,10 @@ namespace Xceed.Wpf.DataGrid return m_groupSortComparers; } - private GroupSortComparer.SortInfo CreateDefaultGroupSortInfo( GroupDescription groupDescription, DataGridItemPropertyBase itemProperty, ListSortDirection sortDirection ) + private IComparer GetSortComparer( GroupDescription groupDescription, DataGridItemPropertyBase itemProperty ) { - DataGridGroupDescription dataGridGroupDescription = groupDescription as DataGridGroupDescription; - IComparer sortComparer = null; + var dataGridGroupDescription = groupDescription as DataGridGroupDescription; + var sortComparer = default( IComparer ); if( dataGridGroupDescription != null ) { @@ -2242,7 +1751,7 @@ namespace Xceed.Wpf.DataGrid sortComparer = ObjectComparer.Singleton; } - return new GroupSortComparer.SortInfo( null, sortDirection, sortComparer ); + return sortComparer; } private void AdjustCurrentAndSendResetNotification( RawItem oldCurrentRawItem, int oldCurrentPosition ) @@ -2257,11 +1766,10 @@ namespace Xceed.Wpf.DataGrid // All the groups will be recreated. No need to trigger the StatFunctions PropertyChanged. this.DeferredOperationManager.ClearInvalidatedGroups(); - // The previous GroupItems or SortItems have changed RootGroup but have not send the RootGroupChanged event. Do it here. - this.OnRootGroupChanged( EventArgs.Empty ); + this.OnPropertyChanged( new PropertyChangedEventArgs( DataGridCollectionViewBase.RootGroupPropertyName ) ); - //Flag that the Collection of groups itself has changed. - this.OnPropertyChanged( new PropertyChangedEventArgs( "Groups" ) ); + // Flag that the Collection of groups itself has changed. + this.OnPropertyChanged( new PropertyChangedEventArgs( DataGridCollectionViewBase.GroupsPropertyName ) ); } private DataGridCollectionViewGroup GetRawItemNewGroup( RawItem rawItem ) @@ -2585,11 +2093,11 @@ namespace Xceed.Wpf.DataGrid if( item != null ) { - RawItem rawItem = this.GetFirstRawItemFromDataItem( item ); + var rawItem = this.GetFirstRawItemFromDataItem( item ); if( rawItem != null ) { // A SortedIndex of -1 means that the RawItem is not in the m_filteredItemList. - if( rawItem.SortedIndex > -1 ) + if( rawItem.SortedIndex >= 0 ) return rawItem.GetGlobalSortedIndex(); } } @@ -2829,79 +2337,9 @@ namespace Xceed.Wpf.DataGrid private List m_filteredItemList; private readonly RawItemMap m_dataItemToRawItemMap = new RawItemMap(); - private PropertyDescriptorCollection m_statisticalProperties; - private List m_tempStatFunctions = new List(); - private bool m_hasGroupSortBasedOnStats; - private int m_sortedItemVersion; private DataGridCollectionView m_currentChildCollectionView; - #region Private Class StatFunctionPropertyDescriptor - - private class StatFunctionPropertyDescriptor : PropertyDescriptor - { - public StatFunctionPropertyDescriptor( string propertyName ) - : base( propertyName, null ) - { - } - - public override bool CanResetValue( object component ) - { - return false; - } - - public override Type ComponentType - { - get - { - return typeof( DataGridCollectionViewGroup ); - } - } - - public override object GetValue( object component ) - { - DataGridCollectionViewGroup group = component as DataGridCollectionViewGroup; - - if( group != null ) - return group.GetStatFunctionValue( this.Name ); - - return null; - } - - public override bool IsReadOnly - { - get - { - return true; - } - } - - public override Type PropertyType - { - get - { - return typeof( object ); - } - } - - public override void ResetValue( object component ) - { - throw new NotSupportedException( "This statistical property is read-only." ); - } - - public override void SetValue( object component, object value ) - { - throw new NotSupportedException( "This statistical property is read-only." ); - } - - public override bool ShouldSerializeValue( object component ) - { - return false; - } - } - - #endregion - #region Private Class EqualityComparerWrapper private class EqualityComparerWrapper : IEqualityComparer @@ -2932,6 +2370,5 @@ namespace Xceed.Wpf.DataGrid } #endregion - } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewBase.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewBase.cs index 3cb5ba7a..7e2f4ac7 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewBase.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewBase.cs @@ -24,63 +24,45 @@ using System.Data; using System.Diagnostics; using System.Globalization; using System.Linq; -using System.Reflection; using System.Threading; using System.Windows; using System.Windows.Data; using System.Windows.Threading; -using System.Xml; using Xceed.Utils.Collections; +using Xceed.Wpf.DataGrid.Utils; namespace Xceed.Wpf.DataGrid { public abstract partial class DataGridCollectionViewBase : CollectionView, IEditableCollectionView, IWeakEventListener, IItemProperties { - #region STATIC MEMBERS + #region Static Fields + + internal static readonly string GroupsPropertyName = PropertyHelper.GetPropertyName( ( DataGridCollectionViewBase c ) => c.Groups ); + internal static readonly string RootGroupPropertyName = PropertyHelper.GetPropertyName( ( DataGridCollectionViewBase c ) => c.RootGroup ); + + #endregion + + #region Static Members internal static string GetPropertyNameFromGroupDescription( GroupDescription groupDescription ) { - PropertyGroupDescription propertyGroupDescription = groupDescription as PropertyGroupDescription; - + var propertyGroupDescription = groupDescription as PropertyGroupDescription; if( propertyGroupDescription != null ) return propertyGroupDescription.PropertyName; - DataGridGroupDescription dataGridGroupDescription = groupDescription as DataGridGroupDescription; - + var dataGridGroupDescription = groupDescription as DataGridGroupDescription; if( dataGridGroupDescription != null ) return dataGridGroupDescription.PropertyName; return null; } - private static List GetDataGridItemProperties( Dictionary fieldDescriptors ) - { - List itemProperties = new List( fieldDescriptors.Count ); - - foreach( KeyValuePair fieldDescriptorKeyValuePair in fieldDescriptors ) - { - ItemsSourceHelper.FieldDescriptor fieldDescriptor = fieldDescriptorKeyValuePair.Value; - - itemProperties.Add( new DataGridItemProperty( - fieldDescriptor.Name, - fieldDescriptor.PropertyDescriptor, - fieldDescriptor.DisplayName, - fieldDescriptor.BindingXPath, - fieldDescriptor.BindingPath, - fieldDescriptor.DataType, - true, - fieldDescriptor.ReadOnly, - fieldDescriptor.OverrideReadOnlyForInsertion, - fieldDescriptor.IsASubRelationship, - fieldDescriptor.ForeignKeyDescription ) ); - } - - return itemProperties; - } - - private static List EmptyDataGridItemPropertyList = new List(); + #endregion - #endregion STATIC MEMBERS +// static DataGridCollectionViewBase() +// { +// Licenser.VerifyLicenseSilently(); +// } private DataGridCollectionViewBase() : base( new object[ 0 ] ) @@ -89,8 +71,6 @@ namespace Xceed.Wpf.DataGrid this.PreConstruct(); m_distinctValues = new DistinctValuesDictionary( this ); - m_autoFilterValues = new ReadOnlyDictionary(); - m_autoFilteredDataGridItemProperties = new ObservableCollection(); m_filteredItemProperties = new List(); m_readOnlyFilteredItemProperties = new ReadOnlyCollection( m_filteredItemProperties ); @@ -110,12 +90,16 @@ namespace Xceed.Wpf.DataGrid bool autoCreateForeignKeyDescriptions ) : this() { + m_desiredItemType = itemType; + + m_itemProperties = new DataGridItemPropertyCollection(); + m_detailDescriptions = new DataGridDetailDescriptionCollection(); + m_defaultPropertyDescriptions = new PropertyDescriptionRouteDictionary(); + this.AutoCreateItemProperties = autoCreateItemProperties; this.AutoCreateDetailDescriptions = autoCreateDetailDescriptions; this.AutoCreateForeignKeyDescriptions = autoCreateForeignKeyDescriptions; - m_desiredItemType = itemType; - if( itemType == null ) { if( source != null ) @@ -124,58 +108,83 @@ namespace Xceed.Wpf.DataGrid } else if( modelSource != null ) { - IQueryable queryable = modelSource as IQueryable; - + var queryable = modelSource as IQueryable; if( queryable != null ) + { itemType = queryable.ElementType; + } } } else { - Type listItemType = ItemsSourceHelper.GetItemTypeFromEnumeration( source ); - - if( listItemType == null ) - listItemType = typeof( object ); - + var listItemType = ItemsSourceHelper.GetItemTypeFromEnumeration( source ) ?? typeof( object ); if( !listItemType.IsAssignableFrom( itemType ) && !itemType.IsAssignableFrom( listItemType ) ) throw new InvalidOperationException( "The itemType is not assignable to the type of the list." ); } - this.SetSource( modelSource, source, itemType, true ); - - // This will create a new ItemProperties/DatatGridDetailDescriptions collection and pre-feed them with the - // ItemProperties/DetailDescriptions detected on the source collection. - // For DataGridCollectionViews not supporting master/detail, the collection will be created but nothing will be inserted. - this.SetupDefaultDetailDescriptions(); + m_modelSource = modelSource; + m_itemType = itemType; + m_enumeration = source; - this.SetupDefaultItemProperties(); this.CreateDefaultCollections( null ); this.RegisterChangedEvents(); + this.SetupCurrent( true ); + this.SetupDefaultPropertyDescriptions(); + this.SetupDefaultDetailDescriptions(); + this.PrepareItemProperties( m_itemProperties ); + + if( this.AutoCreateItemProperties ) + { + ItemsSourceHelper.CreateAndAddItemPropertiesForPropertyDescriptions( m_itemProperties, m_defaultPropertyDescriptions.Values ); + ItemsSourceHelper.AutoDetectSynonyms( this ); + } } internal DataGridCollectionViewBase( IEnumerable collection, DataGridDetailDescription parentDetailDescription, DataGridCollectionViewBase rootDataGridCollectionViewBase ) : this() { - if( !this.CanHaveDetails ) - throw new InvalidOperationException( "An attempt was made to provide a detail description for a source that cannot have details." ); - if( parentDetailDescription == null ) throw new ArgumentNullException( "parentDetailDescription" ); + m_rootDataGridCollectionViewBase = rootDataGridCollectionViewBase; + m_parentDetailDescription = parentDetailDescription; + m_itemProperties = parentDetailDescription.ItemProperties; + m_detailDescriptions = parentDetailDescription.DetailDescriptions; + m_defaultPropertyDescriptions = parentDetailDescription.DefaultPropertyDescriptions; + + m_distinctValuesConstraint = m_parentDetailDescription.DistinctValuesConstraint; + this.AutoCreateDetailDescriptions = parentDetailDescription.AutoCreateDetailDescriptions; this.AutoCreateItemProperties = parentDetailDescription.AutoCreateItemProperties; this.AutoCreateForeignKeyDescriptions = parentDetailDescription.AutoCreateForeignKeyDescriptions; - m_parentDetailDescription = parentDetailDescription; - m_rootDataGridCollectionViewBase = rootDataGridCollectionViewBase; + if( parentDetailDescription.ItemType == null ) + { + parentDetailDescription.ItemType = ItemsSourceHelper.GetItemTypeFromEnumeration( collection ) ?? typeof( object ); + } - Type itemType; - itemType = ItemsSourceHelper.GetItemTypeFromEnumeration( collection ); + m_modelSource = default( object ); + m_itemType = parentDetailDescription.ItemType; + m_enumeration = collection; - if( itemType == null ) - itemType = typeof( object ); + this.CreateDefaultCollections( m_parentDetailDescription ); + this.RegisterChangedEvents(); + this.SetupCurrent( false ); + this.SetupDefaultPropertyDescriptions(); + this.SetupDefaultDetailDescriptions(); + + // Creates the item properties if auto-creation is ON and no one already created them. + if( this.AutoCreateItemProperties && !m_parentDetailDescription.AutoCreateItemPropertiesCompleted ) + { + ItemsSourceHelper.CreateAndAddItemPropertiesForPropertyDescriptions( m_itemProperties, m_defaultPropertyDescriptions.Values ); + ItemsSourceHelper.AutoDetectSynonyms( this ); + + m_parentDetailDescription.AutoCreateItemPropertiesCompleted = true; + } - this.InitializeFromExternalDeclaration( collection, itemType ); + m_filteredItemProperties.Clear(); + + this.PrepareItemProperties( m_itemProperties ); // This is required in the Master/Detail scheme of things! this.ForceRefresh( false, true, false ); @@ -185,7 +194,7 @@ namespace Xceed.Wpf.DataGrid { } - #region ParentCollectionViewSource Property + #region ParentCollectionViewSource Internal Property internal DataGridCollectionViewSourceBase ParentCollectionViewSourceBase { @@ -204,9 +213,9 @@ namespace Xceed.Wpf.DataGrid private DataGridCollectionViewSourceBase m_parentCollectionViewSourceBase; - #endregion ParentCollectionViewSource Property + #endregion - #region NeedsRefresh Property + #region NeedsRefresh Public Property public override bool NeedsRefresh { @@ -216,9 +225,9 @@ namespace Xceed.Wpf.DataGrid } } - #endregion NeedsRefresh Property + #endregion - #region Culture Property + #region Culture Public Property public override CultureInfo Culture { @@ -236,17 +245,16 @@ namespace Xceed.Wpf.DataGrid // apply our properties to the DataGridCollectionView. // // See CollectionViewSource.ApplyPropertiesToView in reflector for a better understanding. - if( ( this.InDeferRefresh ) - && ( m_parentCollectionViewSourceBase != null ) ) + if( ( this.InDeferRefresh ) && ( m_parentCollectionViewSourceBase != null ) ) { m_parentCollectionViewSourceBase.ApplyExtraPropertiesToView( this ); } } } - #endregion Culture Property + #endregion - #region AutoCreateItemProperties Property + #region AutoCreateItemProperties Public Property public bool AutoCreateItemProperties { @@ -260,9 +268,9 @@ namespace Xceed.Wpf.DataGrid } } - #endregion AutoCreateItemProperties Property + #endregion - #region AutoCreateDetailDescriptions Property + #region AutoCreateDetailDescriptions Public Property internal bool AutoCreateDetailDescriptions { @@ -276,9 +284,9 @@ namespace Xceed.Wpf.DataGrid } } - #endregion AutoCreateDetailDescriptions Property + #endregion - #region ParentDetailDescription Property + #region ParentDetailDescription Public Property internal DataGridDetailDescription ParentDetailDescription { @@ -289,9 +297,9 @@ namespace Xceed.Wpf.DataGrid } - #endregion ParentDetailDescription Property + #endregion - #region AutoCreateForeignKeyDescriptions Property + #region AutoCreateForeignKeyDescriptions Public Property public bool AutoCreateForeignKeyDescriptions { @@ -307,7 +315,7 @@ namespace Xceed.Wpf.DataGrid #endregion - #region SyncRoot Property + #region SyncRoot Internal Property internal virtual object SyncRoot { @@ -326,7 +334,7 @@ namespace Xceed.Wpf.DataGrid #endregion - #region DeferredOperationManager Property + #region DeferredOperationManager Internal Property internal DeferredOperationManager DeferredOperationManager { @@ -338,7 +346,7 @@ namespace Xceed.Wpf.DataGrid #endregion - #region InDeferRefresh Property + #region InDeferRefresh Internal Property internal bool InDeferRefresh { @@ -350,7 +358,7 @@ namespace Xceed.Wpf.DataGrid #endregion - #region Loaded Property + #region Loaded Internal Property internal bool Loaded { @@ -366,7 +374,7 @@ namespace Xceed.Wpf.DataGrid #endregion - #region IsRefreshingDestinctValues Property + #region IsRefreshingDestinctValues Internal Property internal bool IsRefreshingDistinctValues { @@ -382,7 +390,7 @@ namespace Xceed.Wpf.DataGrid #endregion - #region Refreshing Property + #region Refreshing Internal Property internal bool Refreshing { @@ -398,7 +406,7 @@ namespace Xceed.Wpf.DataGrid #endregion - #region ModelSource Property + #region ModelSource Internal Property internal object ModelSource { @@ -410,7 +418,7 @@ namespace Xceed.Wpf.DataGrid #endregion - #region ItemEditionIsManuallyHandled Property + #region ItemEditionIsManuallyHandled Private Property private bool ItemEditionIsManuallyHandled { @@ -426,7 +434,7 @@ namespace Xceed.Wpf.DataGrid #endregion - #region CreatingNewItemIsManuallyHandled Property + #region CreatingNewItemIsManuallyHandled Private Property private bool CreatingNewItemIsManuallyHandled { @@ -442,36 +450,71 @@ namespace Xceed.Wpf.DataGrid #endregion - #region ItemPropertiesCreated Property + #region ItemProperties Public Property - private bool ItemPropertiesCreated + public DataGridItemPropertyCollection ItemProperties + { + get + { + return m_itemProperties; + } + } + + #endregion + + #region DefaultItemPropertiesInitialized Private Property + + private bool DefaultItemPropertiesInitialized { get { - return m_flags[ ( int )DataGridCollectionViewBaseFlags.ItemPropertiesCreated ]; + if( m_parentDetailDescription != null ) + return m_parentDetailDescription.DefaultItemPropertiesInitialized; + + return m_flags[ ( int )DataGridCollectionViewBaseFlags.DefaultItemPropertiesInitialized ]; } set { - m_flags[ ( int )DataGridCollectionViewBaseFlags.ItemPropertiesCreated ] = value; + if( m_parentDetailDescription != null ) + { + m_parentDetailDescription.DefaultItemPropertiesInitialized = value; + } + else + { + m_flags[ ( int )DataGridCollectionViewBaseFlags.DefaultItemPropertiesInitialized ] = value; + } } } #endregion - #region ItemProperties Property + #region DefaultPropertyDescriptionsCreated Private Property - public DataGridItemPropertyCollection ItemProperties + private bool DefaultPropertyDescriptionsCreated { get { - Debug.Assert( m_itemProperties != null ); - return m_itemProperties; + if( m_parentDetailDescription != null ) + return m_parentDetailDescription.DefaultPropertyDescriptionsCreated; + + return m_flags[ ( int )DataGridCollectionViewBaseFlags.DefaultPropertyDescriptionsCreated ]; + } + set + { + if( m_parentDetailDescription != null ) + { + m_parentDetailDescription.DefaultPropertyDescriptionsCreated = value; + } + else + { + m_flags[ ( int )DataGridCollectionViewBaseFlags.DefaultPropertyDescriptionsCreated ] = value; + } } } #endregion - #region CanCreateItemPropertiesFormModelSource Property + #region CanCreateItemPropertiesFormModelSource Private Property private bool CanCreateItemPropertiesFromModelSource { @@ -483,7 +526,7 @@ namespace Xceed.Wpf.DataGrid #endregion - #region DetailDeferRefreshes Property + #region DetailDeferRefreshes Internal Property internal List> DetailDeferRefreshes { @@ -497,7 +540,7 @@ namespace Xceed.Wpf.DataGrid #endregion - #region DataGridContext Private Property + #region DataGridContext Internal Property internal DataGridContext DataGridContext { @@ -525,19 +568,6 @@ namespace Xceed.Wpf.DataGrid #endregion - #region IsRootCollectionView Private Property - - private bool IsRootCollectionView - { - get - { - return ( m_rootDataGridCollectionViewBase == null ) - || ( m_rootDataGridCollectionViewBase == this ); - } - } - - #endregion - #region DataGridCollectionViewBase ABSTRACT MEMBERS internal virtual int IndexOfSourceItem( object item ) @@ -559,110 +589,10 @@ namespace Xceed.Wpf.DataGrid internal abstract void ForceRefresh( bool sendResetNotification, bool initialLoad, bool setCurrentToFirstOnInitialLoad ); - #endregion DataGridCollectionViewBase ABSTRACT MEMBERS + #endregion #region SOURCE - private void SetSource( object modelSource, IEnumerable source, Type itemType, bool setCurrentToFirst ) - { - if( this.Loaded ) - throw new InvalidOperationException( "An attempt was made to change the source when the collection view has already been loaded." ); - - m_modelSource = modelSource; - m_itemType = itemType; - - this.SetSourceCore( source, setCurrentToFirst ); - } - - private void SetSourceCore( IEnumerable source, bool setCurrentToFirst ) - { - Debug.Assert( !this.Loaded ); - - if( source == null ) - { - m_enumeration = null; - m_notifyCollectionChanged = null; - m_dataTable = null; - - this.SetCurrentItemAndPositionCore( null, -1, true, true ); - return; - } - - // Unsubscribe from old list event - if( m_notifyCollectionChanged != null ) - { - CollectionChangedEventManager.RemoveListener( m_notifyCollectionChanged, this ); - } - - IBindingList oldBindingList = m_enumeration as IBindingList; - - if( ( oldBindingList != null ) && ( oldBindingList.SupportsChangeNotification ) ) - { - ListChangedEventManager.RemoveListener( oldBindingList, this ); - } - - m_enumeration = source; - m_notifyCollectionChanged = m_enumeration as INotifyCollectionChanged; - - if( m_notifyCollectionChanged != null ) - { - CollectionChangedEventManager.AddListener( m_notifyCollectionChanged, this ); - } - - if( m_notifyCollectionChanged == null ) - { - IBindingList newBindingList = m_enumeration as IBindingList; - - if( ( newBindingList != null ) && ( newBindingList.SupportsChangeNotification ) ) - { - ListChangedEventManager.AddListener( newBindingList, this ); - } - } - - m_dataTable = m_enumeration as DataTable; - - if( m_enumeration != null ) - { - // Position to the first item - IEnumerator enumerator = m_enumeration.GetEnumerator(); - - if( enumerator.MoveNext() ) - { - if( setCurrentToFirst ) - { - this.SetCurrentItemAndPositionCore( enumerator.Current, 0, false, false ); - } - else - { - this.SetCurrentItemAndPositionCore( null, -1, true, false ); - } - } - else - { - this.SetCurrentItemAndPositionCore( null, -1, true, true ); - } - } - else - { - this.SetCurrentItemAndPositionCore( null, -1, true, true ); - } - } - - internal void RemoveSourceChangedListenersForDetail() - { - if( m_notifyCollectionChanged != null ) - { - CollectionChangedEventManager.RemoveListener( m_notifyCollectionChanged, this ); - } - - IBindingList bindingList = m_enumeration as IBindingList; - - if( ( bindingList != null ) && ( bindingList.SupportsChangeNotification ) ) - { - ListChangedEventManager.RemoveListener( bindingList, this ); - } - } - internal IEnumerable Enumeration { get @@ -671,30 +601,12 @@ namespace Xceed.Wpf.DataGrid } } - internal INotifyCollectionChanged NotifyCollectionChanged - { - get - { - return m_notifyCollectionChanged; - } - } - public Type ItemType { get { return m_itemType; } - private set - { - if( m_itemType == value ) - return; - - if( this.ItemPropertiesCreated ) - throw new InvalidOperationException( "An attempt was made to modify the ItemType property after the DataGridItemProperty has been created." ); - - m_itemType = value; - } } internal Type DesiredItemType @@ -709,15 +621,15 @@ namespace Xceed.Wpf.DataGrid { get { - return m_enumeration != null; + return ( m_enumeration != null ); } } - #endregion SOURCE + #endregion #region SOURCE COLLECTION CHANGED HANDLERS - private void NotifyCollectionChanged_CollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) + private void OnItemsSourceCollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) { Debug.Assert( !( this is DataGridVirtualizingCollectionViewBase ), "The DataGridVirtualizingCollectionView is unbound and therefore should never receive a notification from a source." ); @@ -769,11 +681,13 @@ namespace Xceed.Wpf.DataGrid } if( deferredOperation != null ) + { this.ExecuteOrQueueSourceItemOperation( deferredOperation ); + } } } - private void BindingList_ListChanged( object sender, ListChangedEventArgs e ) + private void OnItemsSourceListChanged( object sender, ListChangedEventArgs e ) { Debug.Assert( !( this is DataGridVirtualizingCollectionViewBase ), "The DataGridVirtualizingCollectionView is unbound and therefore should never receive a notification from a source." ); @@ -852,23 +766,6 @@ namespace Xceed.Wpf.DataGrid case ListChangedType.ItemChanged: { var collectionView = this as DataGridCollectionView; - - if( ( collectionView != null ) && collectionView.UpdateChangedPropertyStatsOnly && ( e.PropertyDescriptor != null ) ) - { - collectionView.CalculateChangedPropertyStatsOnly = true; - - var propertyName = e.PropertyDescriptor.Name; - var invalidatedStatFunctions = collectionView.InvalidatedStatFunctions; - - foreach( var statFunction in collectionView.StatFunctions.Where( sf => sf.SourcePropertyNames.Contains( propertyName ) ) ) - { - if( !invalidatedStatFunctions.Contains( statFunction ) ) - { - invalidatedStatFunctions.Add( statFunction ); - } - } - } - deferredOperation = new DeferredOperation( DeferredOperation.DeferredOperationAction.Replace, -1, index, items, index, items ); break; } @@ -904,84 +801,78 @@ namespace Xceed.Wpf.DataGrid private void HandlePropertyDescriptorAdded( PropertyDescriptor property ) { - // setting m_defaultItemProperties, will force the collection view to reanalyze the source to get a new list of default ItemProperties. - m_defaultItemProperties = null; + this.ClearDefaultPropertyDescriptions(); + this.SetupDefaultPropertyDescriptions(); - if( this.AutoCreateItemProperties ) - { - string name = property.Name; + if( !this.AutoCreateItemProperties ) + return; - if( m_itemProperties[ name ] == null ) - { - foreach( DataGridItemPropertyBase itemProperty in this.GetDefaultItemProperties() ) - { - if( itemProperty.Name == name ) - { - this.AddValidItemProperty( itemProperty ); - break; - } - } - } - } + if( m_itemProperties[ property.Name ] != null ) + return; + + var propertyRoute = PropertyRouteParser.Parse( property.Name ); + if( propertyRoute == null ) + return; + + ItemsSourceHelper.CreateAndAddItemPropertyForPropertyDescription( m_itemProperties, m_defaultPropertyDescriptions[ propertyRoute ] ); + ItemsSourceHelper.AutoDetectSynonyms( this, DataGridItemPropertyRoute.Create( ItemsSourceHelper.GetItemPropertyFromProperty( m_itemProperties, propertyRoute ) ) ); } private void HandlePropertyDescriptorChanged( PropertyDescriptor property ) { - // setting m_defaultItemProperties, will force the collection view to reanalyse the source to get a new list of default ItemProperties. - m_defaultItemProperties = null; + this.ClearDefaultPropertyDescriptions(); + this.SetupDefaultPropertyDescriptions(); - if( this.AutoCreateItemProperties ) + if( !this.AutoCreateItemProperties ) + return; + + if( property == null ) { - if( property == null ) + using( m_itemProperties.DeferCollectionChanged() ) { for( int i = m_itemProperties.Count - 1; i >= 0; i-- ) { - DataGridItemProperty oldItemProperty = m_itemProperties[ i ] as DataGridItemProperty; - + var oldItemProperty = m_itemProperties[ i ] as DataGridItemProperty; if( ( oldItemProperty != null ) && ( oldItemProperty.IsAutoCreated ) ) { m_itemProperties.RemoveAt( i ); } } - - foreach( DataGridItemPropertyBase itemProperty in this.GetDefaultItemProperties() ) - { - this.AddValidItemProperty( itemProperty ); - } } - else + + ItemsSourceHelper.CreateAndAddItemPropertiesForPropertyDescriptions( m_itemProperties, m_defaultPropertyDescriptions.Values ); + ItemsSourceHelper.AutoDetectSynonyms( this ); + } + else + { + var oldItemProperty = m_itemProperties[ property.Name ] as DataGridItemProperty; + + if( ( oldItemProperty != null ) && ( oldItemProperty.IsAutoCreated ) ) { - string name = property.Name; - DataGridItemProperty oldItemProperty = m_itemProperties[ name ] as DataGridItemProperty; + // It is better to completely remove the item property and add a new one instead of changing is content. + m_itemProperties.Remove( oldItemProperty ); - if( ( oldItemProperty != null ) && ( oldItemProperty.IsAutoCreated ) ) - { - // It is better to completely remove the item property and add a new one instead of changing is content. - m_itemProperties.Remove( oldItemProperty ); - List defaultItemProperties = this.GetDefaultItemProperties(); + if( m_itemProperties[ property.Name ] != null ) + return; - foreach( DataGridItemPropertyBase itemProperty in defaultItemProperties ) - { - if( itemProperty.Name == name ) - { - this.AddValidItemProperty( itemProperty ); - break; - } - } - } + var propertyRoute = PropertyRouteParser.Parse( property.Name ); + if( propertyRoute == null ) + return; + + ItemsSourceHelper.CreateAndAddItemPropertyForPropertyDescription( m_itemProperties, m_defaultPropertyDescriptions[ propertyRoute ] ); + ItemsSourceHelper.AutoDetectSynonyms( this, DataGridItemPropertyRoute.Create( ItemsSourceHelper.GetItemPropertyFromProperty( m_itemProperties, propertyRoute ) ) ); } } } private void HandlePropertyDescriptorDeleted( PropertyDescriptor property ) { - // setting m_defaultItemProperties, will force the collection view to reanalyse the source to get a new list of default ItemProperties. - m_defaultItemProperties = null; + this.ClearDefaultPropertyDescriptions(); + this.SetupDefaultPropertyDescriptions(); if( this.AutoCreateItemProperties ) { - string name = property.Name; - DataGridItemProperty oldItemProperty = m_itemProperties[ name ] as DataGridItemProperty; + var oldItemProperty = m_itemProperties[ property.Name ] as DataGridItemProperty; if( ( oldItemProperty != null ) && ( oldItemProperty.IsAutoCreated ) ) { @@ -990,186 +881,90 @@ namespace Xceed.Wpf.DataGrid } } - #endregion SOURCE COLLECTION CHANGED HANDLERS + #endregion #region CHILD COLLECTION CHANGED HANDLERS - private void ItemProperties_CollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) + // This method is also called for sub properties. + private void OnItemPropertiesCollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) { - // For detail DataGridCollectionView, this is usually called the first time the DetailDescription is used to generate a DataGridCollectionView. + var addedItems = default( IEnumerable ); + var removedItems = default( IEnumerable ); switch( e.Action ) { case NotifyCollectionChangedAction.Add: - - int newItemsCount = e.NewItems.Count; - - for( int i = 0; i < newItemsCount; i++ ) - { - DataGridItemPropertyBase dataGridItemProperty = e.NewItems[ i ] as DataGridItemPropertyBase; - Debug.Assert( dataGridItemProperty != null ); - - INotifyCollectionChanged collectionChanged = this.GetAutoFilterValues( dataGridItemProperty.Name ) as INotifyCollectionChanged; - - if( collectionChanged != null ) - { - collectionChanged.CollectionChanged += this.OnAutoFilterValuesChanged; - } - - if( dataGridItemProperty.FilterCriterion != null ) - { - this.AddFilteredItemProperty( dataGridItemProperty ); - } - } + addedItems = e.NewItems.Cast(); break; case NotifyCollectionChangedAction.Remove: + removedItems = e.OldItems.Cast(); + break; - int oldItemsCount = e.OldItems.Count; - - using( this.DeferRefresh() ) - { - for( int i = 0; i < oldItemsCount; i++ ) - { - DataGridItemPropertyBase dataGridItemProperty = e.OldItems[ i ] as DataGridItemPropertyBase; - Debug.Assert( dataGridItemProperty != null ); - - string fieldName = dataGridItemProperty.Name; + case NotifyCollectionChangedAction.Replace: + addedItems = e.NewItems.Cast(); + removedItems = e.OldItems.Cast(); + break; - INotifyCollectionChanged collectionChanged = this.GetAutoFilterValues( fieldName ) as INotifyCollectionChanged; + case NotifyCollectionChangedAction.Reset: + throw new NotSupportedException(); + } - if( collectionChanged != null ) - { - collectionChanged.CollectionChanged -= this.OnAutoFilterValuesChanged; - } + if( ( addedItems == null ) && ( removedItems == null ) ) + return; - IList autoFilterValues = collectionChanged as IList; + var deferRefresh = ( this.Loaded ) ? this.DeferRefresh() : null; - if( autoFilterValues != null ) - { - autoFilterValues.Clear(); - } - - this.AutoFilteredDataGridItemProperties.Remove( dataGridItemProperty ); - - // Clear DistinctValues for this item - // NOTE: we use InternalTryGetValue instead of [ ] or TryGetValue to avoid creating the item inside the DistinctValuesDictionary - ReadOnlyObservableHashList readOnlyObservableHashList = null; - - if( ( ( DistinctValuesDictionary )this.DistinctValues ).InternalTryGetValue( fieldName, out readOnlyObservableHashList ) ) - { - IList distinctValues = readOnlyObservableHashList.InnerObservableHashList; - - if( distinctValues != null ) - { - distinctValues.Clear(); - } - } - - if( dataGridItemProperty.FilterCriterion != null ) - { - m_filteredItemProperties.Remove( dataGridItemProperty ); - } - } - } - - break; - - case NotifyCollectionChangedAction.Replace: - int replaceItemsCount = e.NewItems.Count; - - for( int i = 0; i < replaceItemsCount; i++ ) + try + { + if( removedItems != null ) + { + foreach( var itemProperty in removedItems ) { - // If necessary, remove the old ItemProperty and add the new one in the list - // of ItemProperties having their FilterCriterion set. - DataGridItemPropertyBase dataGridItemProperty = e.OldItems[ i ] as DataGridItemPropertyBase; - Debug.Assert( dataGridItemProperty != null ); - - if( dataGridItemProperty.FilterCriterion != null ) - { - m_filteredItemProperties.Remove( dataGridItemProperty ); - } - - dataGridItemProperty = e.NewItems[ i ] as DataGridItemPropertyBase; - Debug.Assert( dataGridItemProperty != null ); - - if( dataGridItemProperty.FilterCriterion != null ) - { - this.AddFilteredItemProperty( dataGridItemProperty ); - } + this.ClearItemProperty( itemProperty ); } - break; - - case NotifyCollectionChangedAction.Reset: - - this.UnregisterAutoFilterCollectionChanged(); + } - using( this.DeferRefresh() ) + if( addedItems != null ) + { + foreach( var itemProperty in addedItems ) { - this.ResetDistinctValues(); - this.ResetAutoFilterValues(); - this.AutoFilteredDataGridItemProperties.Clear(); - m_filteredItemProperties.Clear(); + this.PrepareItemProperty( itemProperty ); } - - break; + } } - } - - private void OnAutoFilterValuesChanged( object sender, NotifyCollectionChangedEventArgs e ) - { - this.OnProxyAutoFilterValuesChanged( this, e ); - - IList autoFilterValues = sender as IList; - - Debug.Assert( autoFilterValues != null ); - string fieldName = this.GetFieldNameFromAutoFitlerValues( autoFilterValues ); - Debug.Assert( fieldName != null ); - Debug.Assert( m_autoFilterValues != null ); - Debug.Assert( m_autoFilterValues[ fieldName ] == autoFilterValues ); - - DataGridItemPropertyBase dataGridItemProperty = this.ItemProperties[ fieldName ]; - Debug.Assert( dataGridItemProperty != null ); - - ObservableCollection autoFilteredItemProperties = this.AutoFilteredDataGridItemProperties; - Debug.Assert( autoFilteredItemProperties != null ); - - // If we are filtered - if( autoFilterValues.Count > 0 ) + finally { - // If this is a newly filtered DataGridItemProperty - if( !autoFilteredItemProperties.Contains( dataGridItemProperty ) ) + lock( this.SyncRoot ) { - autoFilteredItemProperties.Add( dataGridItemProperty ); + lock( this.DeferredOperationManager ) + { + //This is required as the GroupSortStatResultPropertyName property affects this collection, and thus must be updated when there is a change to the ItemsProperties. + this.ClearGroupSortComparers(); + } } - } - else - { - // There is no more filter values for this DataGridItemProperty, - // remove it from m_autoFilteredItems. - if( dataGridItemProperty != null ) + + if( deferRefresh != null ) { - autoFilteredItemProperties.Remove( dataGridItemProperty ); + deferRefresh.Dispose(); } } + } - if( this.AutoFilterMode != AutoFilterMode.None ) - { - AutoFilterValuesChangedEventArgs autoFilterValuesChangedEventArgs = new AutoFilterValuesChangedEventArgs( m_parentDetailDescription, dataGridItemProperty, autoFilterValues, e ); + private void OnItemPropertyPropertyChanged( DataGridItemPropertyBase itemProperty, PropertyChangedEventArgs e ) + { + if( itemProperty == null ) + return; - this.RaiseAutoFilterValuesChangedEvent( autoFilterValuesChangedEventArgs ); - m_excludedItemPropertyFromDistinctValueCalculation = dataGridItemProperty; + var propertyName = e.PropertyName; - try - { - // The refresh may be defered, if it's the case, m_excludedItemPropertyFromDistinctValueCalculation will - // not be considered. This behavior is what we want since a defered refresh can mean aother operation - // altered the items of the source so we want to rebuild the distinct value. - this.Refresh(); - } - finally + if( string.IsNullOrEmpty( propertyName ) || ( propertyName == DataGridItemPropertyBase.ItemPropertiesInternalPropertyName ) ) + { + var itemProperties = itemProperty.ItemPropertiesInternal; + if( itemProperties != null ) { - m_excludedItemPropertyFromDistinctValueCalculation = null; + this.ClearItemProperties( itemProperties ); + this.PrepareItemProperties( itemProperties ); } } } @@ -1209,7 +1004,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion CHILD COLLECTION CHANGED HANDLERS + #endregion #region PROXY EVENTS @@ -1221,26 +1016,6 @@ namespace Xceed.Wpf.DataGrid } } - internal event EventHandler ProxyApplyingFilterCriterias; - - private void OnProxyApplyingFilterCriterias( object sender, EventArgs e ) - { - if( m_rootDataGridCollectionViewBase.ProxyApplyingFilterCriterias != null ) - { - m_rootDataGridCollectionViewBase.ProxyApplyingFilterCriterias( sender, e ); - } - } - - internal event NotifyCollectionChangedEventHandler ProxyAutoFilterValuesChanged; - - private void OnProxyAutoFilterValuesChanged( object sender, NotifyCollectionChangedEventArgs e ) - { - if( m_rootDataGridCollectionViewBase.ProxyAutoFilterValuesChanged != null ) - { - m_rootDataGridCollectionViewBase.ProxyAutoFilterValuesChanged( sender, e ); - } - } - internal event EventHandler ProxyCollectionRefresh; internal void OnProxyCollectionRefresh() @@ -1271,7 +1046,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion PROXY EVENTS + #endregion #region EDIT PROCESS @@ -1306,19 +1081,18 @@ namespace Xceed.Wpf.DataGrid throw new ArgumentNullException( "item" ); endEditCalled = false; - IEditableObject editableObject = ItemsSourceHelper.GetEditableObject( item ); + var editableObject = ItemsSourceHelper.GetEditableObject( item ); // editableObject can be an Xceed datarow when directly inserted as Items in the DataGridControl. if( ( editableObject != null ) && ( !( editableObject is Xceed.Wpf.DataGrid.DataRow ) ) ) { // Keep a copy of the values, because if EndEdit throw ( for a DataView ), we loose the old values. - DataGridItemPropertyCollection itemProperties = this.ItemProperties; - int count = itemProperties.Count; - object[] oldValueBeforeEndEdit = new object[ count ]; + var itemProperties = this.ItemProperties; + var oldValueBeforeEndEdit = new Dictionary( itemProperties.Count ); - for( int i = 0; i < count; i++ ) + foreach( var itemProperty in itemProperties ) { - oldValueBeforeEndEdit[ i ] = itemProperties[ i ].GetValue( item ); + oldValueBeforeEndEdit[ itemProperty ] = ItemsSourceHelper.GetValueFromItemProperty( itemProperty, item ); } try @@ -1326,36 +1100,35 @@ namespace Xceed.Wpf.DataGrid editableObject.EndEdit(); endEditCalled = true; } - catch + finally { - // Since the DataView of MS cancel the edition when EndEdit is throwing, we ensure to restart the edition mode. - editableObject.BeginEdit(); + if( !endEditCalled ) + { + // Since the DataView of MS cancel the edition when EndEdit is throwing, we ensure to restart the editing mode. + editableObject.BeginEdit(); - itemProperties.SuspendUnboundItemPropertyChanged( item ); + itemProperties.SuspendUnboundItemPropertyChanged( item ); - try - { - // restore the oldvalues - for( int i = 0; i < count; i++ ) + try { - DataGridItemPropertyBase itemProperty = itemProperties[ i ]; - - bool readOnly = ( ( item == m_currentAddItem ) - && itemProperty.OverrideReadOnlyForInsertion.HasValue - && itemProperty.OverrideReadOnlyForInsertion.Value ) - ? false - : itemProperty.IsReadOnly; + // restore the oldvalues + foreach( var itemProperty in itemProperties ) + { + var readOnly = ( ( item == m_currentAddItem ) && itemProperty.OverrideReadOnlyForInsertion.HasValue && itemProperty.OverrideReadOnlyForInsertion.Value ) + ? false + : itemProperty.IsReadOnly; - if( !readOnly ) - itemProperties[ i ].SetValue( item, oldValueBeforeEndEdit[ i ] ); + if( !readOnly ) + { + ItemsSourceHelper.SetValueForItemProperty( itemProperty, item, oldValueBeforeEndEdit[ itemProperty ] ); + } + } + } + finally + { + itemProperties.ResumeUnboundItemPropertyChanged( item ); } } - finally - { - itemProperties.ResumeUnboundItemPropertyChanged( item ); - } - - throw; } } } @@ -1451,7 +1224,7 @@ namespace Xceed.Wpf.DataGrid m_parentCollectionViewSourceBase.OnEditCommitted( e ); } - #endregion EDIT PROCESS + #endregion #region INSERTION PROCESS @@ -1538,7 +1311,7 @@ namespace Xceed.Wpf.DataGrid m_parentCollectionViewSourceBase.OnNewItemCanceled( e ); } - #endregion INSERTION PROCESS + #endregion #region DELETION PROCESS @@ -1555,638 +1328,29 @@ namespace Xceed.Wpf.DataGrid throw new InvalidOperationException( "An attempt was made to remove an item from the source collection." ); } - public event EventHandler RemovingItem; - - internal void OnRemovingItem( DataGridRemovingItemEventArgs e ) - { - if( this.RemovingItem != null ) - this.RemovingItem( this, e ); - - if( m_parentCollectionViewSourceBase != null ) - m_parentCollectionViewSourceBase.OnRemovingItem( e ); - } - - public event EventHandler ItemRemoved; - - internal void OnItemRemoved( DataGridItemRemovedEventArgs e ) - { - if( this.ItemRemoved != null ) - this.ItemRemoved( this, e ); - - if( m_parentCollectionViewSourceBase != null ) - m_parentCollectionViewSourceBase.OnItemRemoved( e ); - } - - #endregion DELETION PROCESS - - #region MASTER DETAIL - - private static List EmptyDataGridDetailDescriptionList = new List(); - - internal virtual bool CanHaveDetails - { - get - { - return false; - } - } - - private void DataGridDetailDescriptions_CollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) - { - if( !this.CanHaveDetails ) - throw new InvalidOperationException( "An attempt was made to modify the DetailDescriptions of a " + this.GetType().Name + ", which does not support master detail." ); - - // Set the AutoFilterValuesChanged event for each - // newly added DataGridDetailDescription added to - // collection - int newItemsCount = ( e.NewItems != null ) - ? e.NewItems.Count - : 0; - - int oldItemsCount = ( e.OldItems != null ) - ? e.OldItems.Count - : 0; - - for( int i = 0; i < oldItemsCount; i++ ) - { - DataGridDetailDescription description = e.OldItems[ i ] as DataGridDetailDescription; - - if( description == null ) - continue; - - description.UnregisterAllAutoFilterValuesChangedEvent(); - } - - for( int i = 0; i < newItemsCount; i++ ) - { - DataGridDetailDescription description = e.NewItems[ i ] as DataGridDetailDescription; - - if( description == null ) - continue; - - description.DetailDescriptionAutoFilterValuesChanged = this.RaiseAutoFilterValuesChangedEvent; - } - } - - internal DataGridDetailDescriptionCollection DetailDescriptions - { - get - { - Debug.Assert( m_dataGridDetailDescriptions != null ); - return m_dataGridDetailDescriptions; - } - } - - internal virtual List GetDefaultDetailDescriptions() - { - if( m_defaultDetailDescriptions == null ) - { - if( this.CanCreateDetailDescriptions() ) - { - m_defaultDetailDescriptions = this.CreateDetailDescriptions(); - - // Propagate the AutoCreateForeignKeyDescriptions values to the auto created DataGridDetailDescription. - foreach( var description in m_defaultDetailDescriptions.Where( item => item.IsAutoCreated ) ) - { - description.AutoCreateForeignKeyDescriptions = this.AutoCreateForeignKeyDescriptions; - } - } - else - { - return DataGridCollectionViewBase.EmptyDataGridDetailDescriptionList; - } - } - - return m_defaultDetailDescriptions; - } - - internal virtual bool CanCreateDetailDescriptions() - { - return ( ( m_enumeration != null ) || ( m_itemType != typeof( object ) ) ); - } - - private List CreateDetailDescriptions() - { - //Source collection is a DataTable or a DataTable was detected by looking at the first item in the collection. - if( m_dataTable != null ) - return this.CreateDetailDescriptionsForTable(); - - if( typeof( XmlNode ).IsAssignableFrom( m_itemType ) ) - return new List(); - - //Unbound mode, we do not support Master/Detail in this scenario. - if( typeof( DataRow ).IsAssignableFrom( m_itemType ) ) - return new List(); - - //we do not support Master/Details when Item is a Value type... - if( ItemsSourceHelper.IsValueType( m_itemType ) ) - return new List(); - - //Check if the object is a Entity Framework Entity, before checking for IEnumerable (since Entity Framework does have IEnumerable - //properties, but require special handling )... - if( ItemsSourceHelper.IsEntityFramework( m_itemType ) ) - return DataGridCollectionViewBase.CreateDetailDescriptionsForEntityFramework( m_itemType ); - - //If the first item maps to an object that implements IEnumerable, expand that as a Relation ( and only that )... - if( typeof( IEnumerable ).IsAssignableFrom( m_itemType ) ) - return DataGridCollectionViewBase.CreateDetailDescriptionsForEnumerable(); - - if( typeof( IListSource ).IsAssignableFrom( m_itemType ) ) - return DataGridCollectionViewBase.CreateDetailDescriptionsForListSource(); - - //If the Source collection implements ITypedList - var typedList = m_enumeration as ITypedList; - if( typedList != null ) - return DataGridCollectionViewBase.GetDataGridDetailDescriptions( typedList.GetItemProperties( null ) ); - - var customTypeDescriptor = ItemsSourceHelper.GetCustomTypeDescriptor( m_enumeration, m_itemType ); - if( customTypeDescriptor != null ) - return DataGridCollectionViewBase.GetDataGridDetailDescriptions( customTypeDescriptor.GetProperties() ); - - return DataGridCollectionViewBase.GetDataGridDetailDescriptions( TypeDescriptor.GetProperties( m_itemType ) ); - } - - private static List CreateDetailDescriptionsForEnumerable() - { - List newList = new List( 1 ); - DataGridDetailDescription detailDesc = new EnumerableDetailDescription(); - detailDesc.IsAutoCreated = true; - - newList.Add( detailDesc ); - - return newList; - } - - private static List CreateDetailDescriptionsForListSource() - { - List newList = new List( 1 ); - ListSourceDetailDescription detailDesc = new ListSourceDetailDescription(); - detailDesc.IsAutoCreated = true; - - newList.Add( detailDesc ); - - return newList; - } - - private List CreateDetailDescriptionsForTable() - { - List relations = new List( m_dataTable.ChildRelations.Count ); - foreach( DataRelation relation in m_dataTable.ChildRelations ) - { - DataRelationDetailDescription description = new DataRelationDetailDescription( relation ); - description.IsAutoCreated = true; - relations.Add( description ); - } - - return relations; - } - - private static List CreateDetailDescriptionsForEntityFramework( Type type ) - { - List relations = new List(); - - // Gets all the public properties of the type. - PropertyInfo[] propertyInfos = type.GetProperties( BindingFlags.Instance | BindingFlags.Public ); - - // Loop throught the properties to build up the detail descriptions. - foreach( PropertyInfo propertyInfo in propertyInfos ) - { - Type propertyType = propertyInfo.PropertyType; - - // The property must be of type RelatedEnd and IEnumerable to continue. - - if( ( propertyType.BaseType != null ) - && ( propertyType.BaseType.FullName == "System.Data.Objects.DataClasses.RelatedEnd" ) - && ( typeof( IEnumerable ).IsAssignableFrom( propertyInfo.PropertyType ) ) ) - { - relations.Add( new EntityDetailDescription( propertyInfo.Name ) ); - } - } - - return relations; - } - - private static List GetDataGridDetailDescriptions( PropertyDescriptorCollection properties ) - { - Type enumrableType = typeof( IEnumerable ); - Type listSourceType = typeof( IListSource ); - - List detailDescriptions = new List( properties.Count ); - - foreach( PropertyDescriptor property in properties ) - { - // We only create details for properties that are browsable. - if( !property.IsBrowsable ) - continue; - - if( ItemsSourceHelper.IsASubRelationship( property.PropertyType ) ) - { - PropertyDetailDescription description = new PropertyDetailDescription( property ); - description.IsAutoCreated = true; - detailDescriptions.Add( description ); - } - } - - return detailDescriptions; - } - - #endregion MASTER DETAIL - - #region AUTO FILTERING - - internal event EventHandler AutoFilterValuesChanged; - - public event EventHandler DistinctValuesRefreshNeeded; - - internal AutoFilterMode AutoFilterMode - { - get - { - return m_autoFilterMode; - } - set - { - if( ( !this.CanAutoFilter ) && ( value != AutoFilterMode.None ) ) - throw new NotSupportedException( "This collection view does not support automatic filtering." ); - - if( m_autoFilterMode != value ) - { - m_autoFilterMode = value; - - if( value == AutoFilterMode.None ) - { - this.ResetDistinctValues(); - } - - if( this.Loaded ) - { - this.Refresh(); - } - - this.OnPropertyChanged( new PropertyChangedEventArgs( "AutoFilterMode" ) ); - } - } - } - - public virtual DistinctValuesConstraint DistinctValuesConstraint - { - get - { - return m_distinctValuesConstraint; - } - set - { - if( value != m_distinctValuesConstraint ) - { - using( this.DeferRefresh() ) - { - m_distinctValuesConstraint = value; - - this.RefreshDistinctValues( true ); - } - } - } - } - - public DistinctValuesUpdateMode DistinctValuesUpdateMode - { - get - { - return m_distinctValueUpdateMode; - } - set - { - m_distinctValueUpdateMode = value; - } - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods" )] - public IDictionary DistinctValues - { - get - { - return m_distinctValues; - } - } - - internal IDictionary AutoFilterValues - { - get - { - return m_autoFilterValues; - } - } - - public ICollection GetDistinctValues( string fieldName ) - { - ReadOnlyObservableHashList distinctValues = null; - - this.DistinctValues.TryGetValue( fieldName, out distinctValues ); - - return distinctValues; - } - - internal ObservableCollection AutoFilteredDataGridItemProperties - { - get - { - return m_autoFilteredDataGridItemProperties; - } - } - - internal static void RemoveUnusedDistinctValues( IComparer sortComparer, HashSet currentValues, ObservableHashList cachedValues, object convertNullTo ) - { - bool needsResort = false; - List itemsToDelete = new List(); - int cachedValuesCount = cachedValues.Count; - - // Find no more existing values - for( int i = 0; i < cachedValuesCount; i++ ) - { - object cachedValue = cachedValues[ i ]; - - if( cachedValue == convertNullTo ) - { - cachedValue = null; - } - - if( currentValues.Remove( cachedValue ) ) - { - // remaining items will only be newly added ones - } - else - { - // Item is not currently in column, will be deleted - itemsToDelete.Add( i ); - } - } - - // Remove unused items - int count = itemsToDelete.Count; - - for( int i = count - 1; i >= 0; i-- ) - { - cachedValues.RemoveAt( itemsToDelete[ i ] ); - } - - // Every item not removed from the current values are new values, we add them to columnDistinctValues - needsResort = ( currentValues.Count > 0 ); - - foreach( object key in currentValues ) - { - if( key == null ) - { - cachedValues.Add( convertNullTo ); - } - else - { - cachedValues.Add( key ); - } - } - - if( needsResort ) - { - cachedValues.Sort( sortComparer ); - } - } - - internal void RaiseAutoFilterValuesChangedEvent( AutoFilterValuesChangedEventArgs e ) - { - // This will not be raised for Details since the ParentCollectionViewSourceBase - // is always null for a detail. The event will be raised by the - // DataGridDetailDescription.AutoFilterValuesChanged internal Action - // to assert only 1 event is sent to the user event if there are more than - // 1 DataGridContext expanded. - if( this.AutoFilterValuesChanged != null ) - this.AutoFilterValuesChanged( this, e ); - - if( m_parentCollectionViewSourceBase != null ) - m_parentCollectionViewSourceBase.OnAutoFilterValuesChanged( e ); - } - - internal void RaiseDistinctValuesRefreshNeeded() - { - //The AutoFilterControl is the primary "user" of this events, it will use it to know when to update the DistinctValues when its DropDown gets open. - //However, users can subscribe to it, so they can update the DistinctValues when they use the AutoFilterControl outside the grid. - if( this.DistinctValuesRefreshNeeded != null ) - { - this.DistinctValuesRefreshNeeded( this, EventArgs.Empty ); - } - - if( m_parentCollectionViewSourceBase != null ) - { - m_parentCollectionViewSourceBase.RaiseDistinctValuesRefreshNeeded(); - } - } - - internal IList GetAutoFilterValues( string fieldName ) - { - Debug.Assert( !string.IsNullOrEmpty( fieldName ), "fieldName can't be null" ); - - if( fieldName == null ) - throw new ArgumentNullException( "dataGridItemProperty" ); - - IList autoFilterValues; - - if( !m_autoFilterValues.TryGetValue( fieldName, out autoFilterValues ) ) - { - ObservableHashList hashList = new ObservableHashList(); - autoFilterValues = hashList; - m_autoFilterValues.InternalAdd( fieldName, hashList ); - - // Notify the DetailDescription that it must listen to - // AutoFilterValues CollectionChanged for a specific - // field name and autoFilterValues in order to raise - // the AutoFilterValuesChanged properly - if( m_parentDetailDescription != null ) - m_parentDetailDescription.RegisterAutoFilterValuesChangedEvent( fieldName, hashList ); - } - - return autoFilterValues; - } - - internal void ForceRefreshDistinctValuesForFieldName( string fieldName ) - { - if( this.AutoFilterMode == AutoFilterMode.None ) - return; - - // Avoid multiple refreshes caused by NotifyCollectionChanged events when adding or removing - // values from distinct values lists - if( this.IsRefreshingDistinctValues ) - throw new InvalidOperationException( "An attempt was made to refresh the DataGridCollectionView while it is already in the process of refreshing." ); - - this.IsRefreshingDistinctValues = true; - - try - { - var dataGridItemProperty = this.ItemProperties[ fieldName ]; - if( ( dataGridItemProperty == null ) || ( !dataGridItemProperty.CalculateDistinctValues ) ) - return; - - this.RefreshDistinctValuesForField( dataGridItemProperty ); - } - finally - { - this.IsRefreshingDistinctValues = false; - } - } - - internal abstract void RefreshDistinctValuesForField( DataGridItemPropertyBase dataGridItemProperty ); - - internal void ForceRefreshDistinctValues( bool filteredItemsChanged ) - { - if( this.AutoFilterMode == AutoFilterMode.None ) - return; - - // Avoid multiple refreshes caused by NotifyCollectionChanged events when adding or removing - // values from distinct values lists - if( this.IsRefreshingDistinctValues ) - throw new InvalidOperationException( "An attempt was made to refresh the DataGridCollectionView while it is already in the process of refreshing." ); - - this.IsRefreshingDistinctValues = true; - - try - { - for( int propertyIndex = 0; propertyIndex < m_itemProperties.Count; propertyIndex++ ) - { - var dataGridItemProperty = m_itemProperties[ propertyIndex ]; - - if( !dataGridItemProperty.CalculateDistinctValues ) - continue; - - if( dataGridItemProperty == m_excludedItemPropertyFromDistinctValueCalculation ) - continue; - - // No modifications to filtered items, do not calculated Distinct Values for this DataGridItemProperty - if( ( this.DistinctValuesConstraint != DistinctValuesConstraint.All ) && ( !filteredItemsChanged ) ) - continue; - - this.RefreshDistinctValuesForField( dataGridItemProperty ); - } - } - finally - { - this.IsRefreshingDistinctValues = false; - } - } - - internal void RefreshDistinctValues( bool filteredItemsChanged ) - { - Debug.Assert( !( this is DataGridVirtualizingCollectionViewBase ) ); - - this.EnsureThread(); - - lock( this.SyncRoot ) - { - lock( this.DeferredOperationManager ) - { - if( m_autoFilterMode == DataGrid.AutoFilterMode.None ) - return; - - if( filteredItemsChanged ) - { - this.ExecuteOrQueueSourceItemOperation( DeferredOperation.RefreshDistinctValuesOperationWithFilteredItemsChanged ); - } - else - { - this.ExecuteOrQueueSourceItemOperation( DeferredOperation.RefreshDistinctValuesOperation ); - } - } - } - } - - private void ResetDistinctValues() - { - //The internal ReadOnlyObservableHashList's must be removed, so they are re-created and properly populated when they are queried again. - m_distinctValues.InternalClear(); - } - - private void ResetAutoFilterValues() - { - if( m_autoFilterValues == null ) - return; - - foreach( IList values in m_autoFilterValues.Values ) - { - if( values != null ) - values.Clear(); - } - } - - private string GetFieldNameFromAutoFitlerValues( IList targetAutoFilterValues ) - { - IDictionary autoFilterValues = this.AutoFilterValues; - - foreach( string fieldName in autoFilterValues.Keys ) - { - if( autoFilterValues[ fieldName ] == targetAutoFilterValues ) - return fieldName; - } - - return null; - } - - #endregion AUTO FILTERING - - #region FILTER CRITERION - - public FilterCriteriaMode FilterCriteriaMode - { - get - { - return m_filterCriteriaMode; - } - - set - { - if( value != m_filterCriteriaMode ) - { - m_filterCriteriaMode = value; - this.ReapplyFilterCriterion(); - this.OnPropertyChanged( new PropertyChangedEventArgs( "FilterCriteriaMode" ) ); - } - } - } - - internal ReadOnlyCollection FilteredCriterionItemProperties - { - get - { - return m_readOnlyFilteredItemProperties; - } - } - - // We use the FilterCriterionChanged event instead of the generic PropertyChanged - // event to be more efficient and be advised if any of the FilterCriterion hierarchy - // sub-property changes. - private void ItemProperties_FilterCriterionChanged( object sender, EventArgs e ) - { - this.ReapplyFilterCriterion(); - } + public event EventHandler RemovingItem; - private void ReapplyFilterCriterion() + internal void OnRemovingItem( DataGridRemovingItemEventArgs e ) { - this.OnProxyApplyingFilterCriterias( this, EventArgs.Empty ); - - m_filteredItemProperties.Clear(); - - foreach( DataGridItemPropertyBase itemProperty in this.ItemProperties ) - { - if( itemProperty.FilterCriterion != null ) - { - this.AddFilteredItemProperty( itemProperty ); - } - } + if( this.RemovingItem != null ) + this.RemovingItem( this, e ); - this.Refresh(); + if( m_parentCollectionViewSourceBase != null ) + m_parentCollectionViewSourceBase.OnRemovingItem( e ); } - private void AddFilteredItemProperty( DataGridItemPropertyBase itemProperty ) + public event EventHandler ItemRemoved; + + internal void OnItemRemoved( DataGridItemRemovedEventArgs e ) { - m_filteredItemProperties.Add( itemProperty ); + if( this.ItemRemoved != null ) + this.ItemRemoved( this, e ); + + if( m_parentCollectionViewSourceBase != null ) + m_parentCollectionViewSourceBase.OnItemRemoved( e ); } - #endregion FILTER CRITERION + #endregion #region CURRENCY MANAGEMENT @@ -2295,7 +1459,7 @@ namespace Xceed.Wpf.DataGrid m_flags[ ( int )DataGridCollectionViewBaseFlags.IsCurrentAfterLast ] = isCurrentAfterLast; } - #endregion CURRENCY MANAGEMENT + #endregion #region DEFERRED OPERATIONS HANDLING @@ -2432,7 +1596,7 @@ namespace Xceed.Wpf.DataGrid m_deferredAddNewOperationManager.Add( deferredOperation ); } - #endregion DEFERRED OPERATIONS HANDLING + #endregion protected override void OnCollectionChanged( NotifyCollectionChangedEventArgs args ) { @@ -2447,7 +1611,7 @@ namespace Xceed.Wpf.DataGrid base.OnCollectionChanged( args ); } - internal virtual void ProcessInvalidatedGroupStats( HashSet invalidatedGroups ) + internal virtual void ProcessInvalidatedGroupStats( HashSet invalidatedGroups, bool resortGroups ) { } @@ -2462,35 +1626,12 @@ namespace Xceed.Wpf.DataGrid internal virtual void CreateDefaultCollections( DataGridDetailDescription parentDetailDescription ) { - Debug.Assert( parentDetailDescription == null || this.CanHaveDetails ); - - m_sortDescriptions = ( parentDetailDescription == null ) ? new DataGridSortDescriptionCollection() : - parentDetailDescription.SortDescriptions as DataGridSortDescriptionCollection; + Debug.Assert( parentDetailDescription == null ); + m_sortDescriptions = ( parentDetailDescription == null ) ? new DataGridSortDescriptionCollection() : parentDetailDescription.SortDescriptions as DataGridSortDescriptionCollection; m_groupDescriptions = ( parentDetailDescription == null ) ? new GroupDescriptionCollection() : parentDetailDescription.GroupDescriptions; } - internal virtual void RegisterChangedEvents() - { - ( ( INotifyCollectionChanged )m_sortDescriptions ).CollectionChanged += new NotifyCollectionChangedEventHandler( this.OnSortDescriptionsChanged ); - ( ( INotifyCollectionChanged )m_groupDescriptions ).CollectionChanged += new NotifyCollectionChangedEventHandler( this.OnGroupDescriptionsChanged ); - - ItemPropertyGroupSortStatNameChangedEventManager.AddListener( m_itemProperties, this ); - } - - internal virtual void UnregisterChangedEvents() - { - ( ( INotifyCollectionChanged )m_sortDescriptions ).CollectionChanged -= this.OnSortDescriptionsChanged; - ( ( INotifyCollectionChanged )m_groupDescriptions ).CollectionChanged -= this.OnGroupDescriptionsChanged; - - ItemPropertyGroupSortStatNameChangedEventManager.RemoveListener( m_itemProperties, this ); - - m_itemProperties.CollectionChanged -= this.ItemProperties_CollectionChanged; - m_itemProperties.FilterCriterionChanged -= this.ItemProperties_FilterCriterionChanged; - - this.UnregisterAutoFilterCollectionChanged(); - } - internal bool IsSourceSupportingChangeNotification { get @@ -2505,355 +1646,357 @@ namespace Xceed.Wpf.DataGrid m_detailDeferRefreshes = new List>(); } - private void SetupDefaultDetailDescriptions() + internal void Dispose() { - if( this.CanHaveDetails ) + if( this.ParentCollectionViewSourceBase != null ) { - List defaultDetailDescriptions = this.GetDefaultDetailDescriptions(); + this.ParentCollectionViewSourceBase = null; - if( this.AutoCreateDetailDescriptions ) - { - m_dataGridDetailDescriptions = new DataGridDetailDescriptionCollection( defaultDetailDescriptions ); - } - else - { - m_dataGridDetailDescriptions = new DataGridDetailDescriptionCollection( new List() ); - } - - m_dataGridDetailDescriptions.DefaultDetailDescriptions = defaultDetailDescriptions; - } - else - { - // We still create the DetailDescriptions collection but will validate on any modification that the collection view does - // in fact support master/detail. - m_dataGridDetailDescriptions = new DataGridDetailDescriptionCollection( new List() ); + this.ClearDefaultPropertyDescriptions(); + this.ClearItemProperties(); } - CollectionChangedEventManager.AddListener( m_dataGridDetailDescriptions, this ); + this.ClearItemProperties( m_itemProperties ); + this.UnregisterChangedEvents(); } - private void UnregisterAutoFilterCollectionChanged() + private void SetupDefaultDetailDescriptions() { - if( m_autoFilterValues != null ) + if( ( m_parentDetailDescription != null ) && m_parentDetailDescription.AutoCreateDetailDescriptionsCompleted ) + return; + + if( this.AutoCreateDetailDescriptions) { - foreach( INotifyCollectionChanged notifyCollectionChanged in m_autoFilterValues.Values ) + var defaultDetailDescriptions = ItemsSourceHelper.CreateDetailDescriptions( m_itemType, m_enumeration ); + if( defaultDetailDescriptions != null ) { - notifyCollectionChanged.CollectionChanged -= this.OnAutoFilterValuesChanged; + foreach( var detailDescription in defaultDetailDescriptions ) + { + if( m_detailDescriptions[ detailDescription.RelationName ] != null ) + continue; + + if( detailDescription.IsAutoCreated ) + { + // Propagate the AutoCreateForeignKeyDescriptions values to the auto created DataGridDetailDescription. + detailDescription.AutoCreateForeignKeyDescriptions = this.AutoCreateForeignKeyDescriptions; + } + + m_detailDescriptions.Add( detailDescription ); + } } } + + if( m_parentDetailDescription != null ) + { + m_parentDetailDescription.AutoCreateDetailDescriptionsCompleted = true; + } } - private void InitializeFromExternalDeclaration( IEnumerable collection, Type itemType ) + private void SetupCurrent( bool setToFirstItem ) { - Debug.Assert( m_parentDetailDescription.ItemProperties != null ); - Debug.Assert( m_parentDetailDescription.DetailDescriptions != null ); - Debug.Assert( m_parentDetailDescription.StatFunctions != null ); - Debug.Assert( m_parentDetailDescription.SortDescriptions != null ); - Debug.Assert( m_parentDetailDescription.GroupDescriptions != null ); - Debug.Assert( itemType != null ); - Debug.Assert( m_parentDetailDescription.AutoFilterValues != null ); - Debug.Assert( m_parentDetailDescription.AutoFilteredItems != null ); - - m_itemProperties = m_parentDetailDescription.ItemProperties; - - //Ensure that the default item properties and the item type is set on the ItemProperties collection - if( m_itemProperties.ItemType == null ) - m_itemProperties.ItemType = itemType; - - m_dataGridDetailDescriptions = m_parentDetailDescription.DetailDescriptions; - - this.CreateDefaultCollections( m_parentDetailDescription ); - - m_autoFilterMode = m_parentDetailDescription.AutoFilterMode; - m_autoFilterValues = m_parentDetailDescription.AutoFilterValues as ReadOnlyDictionary; - m_autoFilteredDataGridItemProperties = m_parentDetailDescription.AutoFilteredItems; - m_distinctValuesConstraint = m_parentDetailDescription.DistinctValuesConstraint; - m_filterCriteriaMode = m_parentDetailDescription.FilterCriteriaMode; - - //Register to the change notifications for the Group/Sort descriptions collections - this.RegisterChangedEvents(); - - // - then call the SetSource, with the source and the itemType... - this.SetSource( null, collection, itemType, false ); - + Debug.Assert( !this.Loaded ); - //cross-initialize the DefaultDetailDescriptions of the DataGridCollectionView and/or DataGridDetailDescriptionCollection - if( m_dataGridDetailDescriptions.DefaultDetailDescriptions != null ) - { - m_defaultDetailDescriptions = new List( m_dataGridDetailDescriptions.DefaultDetailDescriptions ); - } - else - { - m_dataGridDetailDescriptions.DefaultDetailDescriptions = new List( this.GetDefaultDetailDescriptions() ); - } + var enumerator = ( m_enumeration != null ) ? m_enumeration.GetEnumerator() : null; - //cross-initialize the DefaultItemProperties of the DataGridCollectionView and/or DataGridItemPropertyCollection - if( m_itemProperties.DefaultItemProperties != null ) - { - m_defaultItemProperties = new List( m_itemProperties.DefaultItemProperties ); - } - else + try { - m_itemProperties.DefaultItemProperties = new List( this.GetDefaultItemProperties() ); + if( ( enumerator != null ) && enumerator.MoveNext() ) + { + if( setToFirstItem ) + { + this.SetCurrentItemAndPositionCore( enumerator.Current, 0, false, false ); + } + else + { + this.SetCurrentItemAndPositionCore( null, -1, true, false ); + } + } + else + { + this.SetCurrentItemAndPositionCore( null, -1, true, true ); + } } - - // Creates the item properties if auto-creation is ON and no one already created them. - if( ( this.AutoCreateItemProperties ) - && ( !m_parentDetailDescription.AutoCreateItemPropertiesCompleted ) ) + finally { - this.DetectSynonyms( m_itemProperties ); - - foreach( DataGridItemPropertyBase itemProperty in m_defaultItemProperties ) + var disposable = enumerator as IDisposable; + if( disposable != null ) { - this.AddValidItemProperty( itemProperty ); + disposable.Dispose(); } - - m_parentDetailDescription.AutoCreateItemPropertiesCompleted = true; } + } - // List for ItemProperties changes to be able to refresh when AutoFilterValues changes - m_itemProperties.CollectionChanged += this.ItemProperties_CollectionChanged; - m_itemProperties.FilterCriterionChanged += this.ItemProperties_FilterCriterionChanged; + private void RegisterChangedEvents() + { + this.RegisterSourceChanged( m_enumeration ); - // Register CollectionChanged for AutoFiltering on every DataGridItemProperties - // already in ItemProperties since they are already defined - foreach( DataGridItemPropertyBase dataGridItemProperty in m_itemProperties ) - { - INotifyCollectionChanged collectionChanged = this.GetAutoFilterValues( dataGridItemProperty.Name ) as INotifyCollectionChanged; + CollectionChangedEventManager.AddListener( m_sortDescriptions, this ); + CollectionChangedEventManager.AddListener( m_groupDescriptions, this ); - if( collectionChanged != null ) - collectionChanged.CollectionChanged += new NotifyCollectionChangedEventHandler( this.OnAutoFilterValuesChanged ); - } + ItemPropertyGroupSortStatNameChangedEventManager.AddListener( m_itemProperties, this ); - // Creates the detail descriptions if auto-creation is ON no one already created them. - if( ( this.AutoCreateDetailDescriptions ) - && ( !m_parentDetailDescription.AutoCreateDetailDescriptionsCompleted ) ) + if( m_parentDetailDescription == null ) { - List defaultDetailDescriptions = this.GetDefaultDetailDescriptions(); - - foreach( DataGridDetailDescription detailDescription in defaultDetailDescriptions ) - { - if( m_dataGridDetailDescriptions[ detailDescription.RelationName ] == null ) - m_dataGridDetailDescriptions.Add( detailDescription ); - } - - m_parentDetailDescription.AutoCreateDetailDescriptionsCompleted = true; + InitializeItemPropertyEventManager.AddListener( m_itemProperties, this ); + CollectionChangedEventManager.AddListener( m_detailDescriptions, this ); } + } - m_filteredItemProperties.Clear(); + private void UnregisterChangedEvents() + { + this.UnregisterSourceChanged( m_enumeration ); - foreach( DataGridItemPropertyBase itemProperty in m_itemProperties ) - { - // Set default value for CalculateDistinctValues if not explicitly set - if( !itemProperty.IsCalculateDistinctValuesInitialized ) - itemProperty.CalculateDistinctValues = m_parentDetailDescription.DefaultCalculateDistinctValues; + CollectionChangedEventManager.RemoveListener( m_sortDescriptions, this ); + CollectionChangedEventManager.RemoveListener( m_groupDescriptions, this ); - if( itemProperty.FilterCriterion != null ) - { - this.AddFilteredItemProperty( itemProperty ); - } - } + ItemPropertyGroupSortStatNameChangedEventManager.RemoveListener( m_itemProperties, this ); - // We must manually add AutoFilterDataGridItemProperties if some AutoFilterValues were specified a the DataGridDetailDescription - // since those are used to know in which order filter were applied. Normally, those DataGridItemProperties are - // added in OnAutoFilterValuesChanged because the - if( m_autoFilterValues != null ) + if( m_parentDetailDescription == null ) { - foreach( string key in m_autoFilterValues.Keys ) - { - IList autoFilterValues = m_autoFilterValues[ key ]; - - if( ( autoFilterValues != null ) && ( autoFilterValues.Count > 0 ) ) - { - DataGridItemPropertyBase dataGridItemProperty = m_itemProperties[ key ]; - - if( dataGridItemProperty != null ) - { - if( m_autoFilteredDataGridItemProperties.Contains( dataGridItemProperty ) == false ) - m_autoFilteredDataGridItemProperties.Add( dataGridItemProperty ); - } - } - } + InitializeItemPropertyEventManager.RemoveListener( m_itemProperties, this ); + CollectionChangedEventManager.RemoveListener( m_detailDescriptions, this ); } } - private void SetupDefaultItemProperties() + private void RegisterSourceChanged( IEnumerable source ) { - m_itemProperties = new DataGridItemPropertyCollection(); - m_itemProperties.ItemType = m_itemType; - - // Listen for ItemProperties changes to be able to refresh when AutoFilterValues changes - m_itemProperties.CollectionChanged += this.ItemProperties_CollectionChanged; - m_itemProperties.FilterCriterionChanged += this.ItemProperties_FilterCriterionChanged; + if( source == null ) + return; - // Calling GetDefaultItemProperties will also cache the result in m_defaultItemProperties - // if able to detect properties - List defaultItemProperties = this.GetDefaultItemProperties(); + var collectionChanged = source as INotifyCollectionChanged; + var bindingList = source as IBindingList; - if( this.AutoCreateItemProperties ) + if( collectionChanged != null ) { - // Add new auto created item properties - foreach( DataGridItemPropertyBase defaultProperty in defaultItemProperties ) - { - this.AddValidItemProperty( defaultProperty ); - } + CollectionChangedEventManager.AddListener( collectionChanged, this ); + } + else if( ( bindingList != null ) && bindingList.SupportsChangeNotification ) + { + ListChangedEventManager.AddListener( bindingList, this ); } + } - if( ( m_itemProperties.DefaultItemProperties == null ) && ( m_defaultItemProperties != null ) ) - m_itemProperties.DefaultItemProperties = new List( m_defaultItemProperties ); + private void UnregisterSourceChanged( IEnumerable source ) + { + if( source == null ) + return; - //no need to cycle through the content of the ItemProperties collection to update them since - //they originate from the default anyway. + var collectionChanged = source as INotifyCollectionChanged; + if( collectionChanged != null ) + { + CollectionChangedEventManager.RemoveListener( collectionChanged, this ); + } } - private void AddValidItemProperty( DataGridItemPropertyBase itemProperty ) + private void RegisterItemProperties( DataGridItemPropertyCollection itemProperties ) { - if( !itemProperty.Browsable ) + if( itemProperties == null ) return; - if( itemProperty.IsASubRelationship ) - return; + CollectionChangedEventManager.AddListener( itemProperties, this ); + } - if( m_itemProperties[ itemProperty.Name ] != null ) + private void UnregisterItemProperties( DataGridItemPropertyCollection itemProperties ) + { + if( itemProperties == null ) return; - m_itemProperties.Add( itemProperty ); + CollectionChangedEventManager.RemoveListener( itemProperties, this ); } - private List GetDefaultItemProperties() + private void RegisterItemProperty( DataGridItemPropertyBase itemProperty ) { - if( m_defaultItemProperties == null ) - { - if( this.CanCreateItemProperties() ) - { - m_defaultItemProperties = this.CreateItemProperties(); - - // Set the synonyms on the item properties of the detail collection. - this.DetectSynonyms( m_defaultItemProperties ); - } - else - { - return DataGridCollectionViewBase.EmptyDataGridItemPropertyList; - } - } + if( itemProperty == null ) + return; - return m_defaultItemProperties; + PropertyChangedEventManager.AddListener( itemProperty, this, DataGridItemPropertyBase.ItemPropertiesInternalPropertyName ); } - private List CreateItemProperties() + private void UnregisterItemProperty( DataGridItemPropertyBase itemProperty ) { - List itemProperties = null; + if( itemProperty == null ) + return; - // That call will not always return existing property - // PropertyDescriptor, with an equivalent of a PropertyPath in is name, are also created for each sub index of a JaggedArray for example - this.ItemPropertiesCreated = true; + PropertyChangedEventManager.RemoveListener( itemProperty, this, DataGridItemPropertyBase.ItemPropertiesInternalPropertyName ); + } - DataTable modelDataTable = ( m_dataTable != null ) ? m_dataTable : m_modelSource as DataTable; + private void PrepareItemProperties( DataGridItemPropertyCollection itemProperties ) + { + if( itemProperties == null ) + return; - if( modelDataTable != null ) - { - itemProperties = this.CreateItemPropertiesForTable(); - } - else if( typeof( DataRow ).IsAssignableFrom( m_itemType ) ) + foreach( var itemProperty in itemProperties ) { - itemProperties = new List(); + this.PrepareItemProperty( itemProperty ); } + this.RegisterItemProperties( itemProperties ); + } + + private void ClearItemProperties( DataGridItemPropertyCollection itemProperties ) + { if( itemProperties == null ) + return; + + foreach( var itemProperty in itemProperties ) { - Dictionary fieldDescriptors = ItemsSourceHelper.GetFields( m_enumeration, m_itemType ); - itemProperties = DataGridCollectionViewBase.GetDataGridItemProperties( fieldDescriptors ); + this.ClearItemProperty( itemProperty ); } - return itemProperties; + this.UnregisterItemProperties( itemProperties ); } - private List CreateItemPropertiesForTable() + private void PrepareItemProperty( DataGridItemPropertyBase itemProperty ) { - DataTable modelDataTable = ( m_dataTable != null ) ? m_dataTable : m_modelSource as DataTable; - - Debug.Assert( modelDataTable != null, - "This method should not have been called in the first place if both m_dataTable and m_sourceSchema are null." ); + if( itemProperty == null ) + return; + // Set default value for CalculateDistinctValues if not explicitly set. + if( !itemProperty.IsCalculateDistinctValuesInitialized && ( m_parentDetailDescription != null ) ) + { + itemProperty.CalculateDistinctValues = m_parentDetailDescription.DefaultCalculateDistinctValues; + } - DataColumnCollection columns = modelDataTable.Columns; - int columnCount = columns.Count; - List properties = new List( columnCount ); + var propertyPath = PropertyRouteParser.Parse( itemProperty ); - for( int i = 0; i < columnCount; i++ ) - { - DataColumn column = columns[ i ]; + this.RegisterItemProperty( itemProperty ); + this.PrepareItemProperties( itemProperty.ItemPropertiesInternal ); + } - DataGridItemProperty property = new DataGridItemProperty( - new DataRowColumnPropertyDescriptor( column ), true ); + private void ClearItemProperty( DataGridItemPropertyBase itemProperty ) + { + if( itemProperty == null ) + return; - property.Title = column.Caption; - properties.Add( property ); - } + this.ClearItemProperties( itemProperty.ItemPropertiesInternal ); + this.UnregisterItemProperty( itemProperty ); - return properties; + var propertyPath = PropertyRouteParser.Parse( itemProperty ); } - private void DetectSynonyms( IEnumerable itemProperties ) + private void SetupDefaultPropertyDescriptions() { - // The root CollectionView does not need to have its ItemProperties binded. - if( this.IsRootCollectionView || ( itemProperties == null ) ) + if( this.DefaultPropertyDescriptionsCreated ) return; - var rootItemsProperties = m_rootDataGridCollectionViewBase.ItemProperties; - Debug.Assert( rootItemsProperties != null ); + var modelDataTable = ( m_enumeration as DataTable ) ?? ( m_modelSource as DataTable ); - foreach( var itemProperty in itemProperties ) + if( this.CanCreateItemProperties() ) + { + this.DefaultItemPropertiesInitialized = false; + this.DefaultPropertyDescriptionsCreated = true; + + ItemsSourceHelper.SetPropertyDescriptions( m_defaultPropertyDescriptions, modelDataTable, m_enumeration, m_itemType, true ); + } + + if( !this.DefaultItemPropertiesInitialized ) { - // A Synonym is already set. - if( itemProperty.Synonym != null ) - continue; + this.DefaultItemPropertiesInitialized = true; - // Bind the DataGridItemProperty to a DataGridItemProperty of the root CollectionView. - var matchingItemProperty = rootItemsProperties[ itemProperty.Name ]; - if( ( matchingItemProperty != null ) && ( matchingItemProperty.DataType == itemProperty.DataType ) ) + // Initialize the item properties according to the default property descriptions. + foreach( var itemProperty in m_itemProperties ) { - itemProperty.SetSynonym( matchingItemProperty.Name ); + var itemPropertyRoute = DataGridItemPropertyRoute.Create( itemProperty ); + + ItemsSourceHelper.SetPropertyDescriptionsFromItemProperty( m_defaultPropertyDescriptions, modelDataTable, m_enumeration, m_itemType, itemPropertyRoute ); + ItemsSourceHelper.InitializePropertyDescriptions( m_defaultPropertyDescriptions, itemPropertyRoute, m_itemType, this.DefaultPropertyDescriptionsCreated ); } } } + private void ClearDefaultPropertyDescriptions() + { + this.DefaultItemPropertiesInitialized = false; + this.DefaultPropertyDescriptionsCreated = false; + + m_defaultPropertyDescriptions.Clear(); + } + + private void ClearItemProperties() + { + m_itemProperties.Clear(); + } + #region IWeakEventListener Members bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) + { + return this.OnReceiveWeakEvent( managerType, sender, e ); + } + + protected virtual bool OnReceiveWeakEvent( Type managerType, object sender, EventArgs e ) { if( managerType == typeof( CollectionChangedEventManager ) ) { - if( sender is DataGridDetailDescriptionCollection ) + var eventArgs = ( NotifyCollectionChangedEventArgs )e; + + if( sender == this.SortDescriptions ) { - this.DataGridDetailDescriptions_CollectionChanged( sender, ( NotifyCollectionChangedEventArgs )e ); + this.OnSortDescriptionsChanged( sender, eventArgs ); } - else + else if( sender == this.GroupDescriptions ) { - this.NotifyCollectionChanged_CollectionChanged( sender, ( NotifyCollectionChangedEventArgs )e ); + this.OnGroupDescriptionsChanged( sender, eventArgs ); + } + else if( sender == this.Enumeration ) + { + this.OnItemsSourceCollectionChanged( sender, eventArgs ); + } + else if( sender is DataGridItemPropertyCollection ) + { + this.OnItemPropertiesCollectionChanged( sender, eventArgs ); } - - return true; } + else if( managerType == typeof( PropertyChangedEventManager ) ) + { + var eventArgs = ( PropertyChangedEventArgs )e; + var itemProperty = sender as DataGridItemPropertyBase; - if( managerType == typeof( ListChangedEventManager ) ) + if( itemProperty != null ) + { + this.OnItemPropertyPropertyChanged( itemProperty, eventArgs ); + } + } + else if( managerType == typeof( ListChangedEventManager ) ) { - this.BindingList_ListChanged( sender, ( ListChangedEventArgs )e ); - return true; + if( sender == this.Enumeration ) + { + this.OnItemsSourceListChanged( sender, ( ListChangedEventArgs )e ); + } + } + else if( managerType == typeof( ItemPropertyGroupSortStatNameChangedEventManager ) ) + { + if( sender == this.ItemProperties ) + { + this.ClearGroupSortComparers(); + } } + else if( managerType == typeof( InitializeItemPropertyEventManager ) ) + { + var eventArgs = ( InitializeItemPropertyEventArgs )e; + + if( sender == this.ItemProperties ) + { + var itemProperty = eventArgs.ItemProperty; + var itemPropertyRoute = DataGridItemPropertyRoute.Create( itemProperty ); + var modelDataTable = ( m_enumeration as DataTable ) ?? ( m_modelSource as DataTable ); - if( managerType == typeof( ItemPropertyGroupSortStatNameChangedEventManager ) ) + ItemsSourceHelper.SetPropertyDescriptionsFromItemProperty( m_defaultPropertyDescriptions, modelDataTable, m_enumeration, m_itemType, itemPropertyRoute ); + ItemsSourceHelper.InitializePropertyDescriptions( m_defaultPropertyDescriptions, itemPropertyRoute, m_itemType, this.DefaultPropertyDescriptionsCreated ); + ItemsSourceHelper.AutoDetectSynonyms( this, itemPropertyRoute ); + } + } + else { - this.ClearGroupSortComparers(); - return true; + return false; } - return false; + return true; } - #endregion IWeakEventListener Members + #endregion - #region ICollectionView MEMBERS + #region ICollectionView Members public override IDisposable DeferRefresh() { @@ -2992,14 +2135,6 @@ namespace Xceed.Wpf.DataGrid } } - internal virtual bool CanAutoFilter - { - get - { - return true; - } - } - public override Predicate Filter { get @@ -3027,7 +2162,7 @@ namespace Xceed.Wpf.DataGrid return true; } - #endregion ICollectionView MEMBERS + #endregion #region IEditableCollectionView @@ -3076,9 +2211,7 @@ namespace Xceed.Wpf.DataGrid int newItemIndex; object newItem = ItemsSourceHelper.AddNewDataItem( this.Enumeration, null, out newItemIndex ); - this.SetCurrentAddNew( - newItem, - newItemIndex ); + this.SetCurrentAddNew( newItem, newItemIndex ); } DataGridItemEventArgs initializingNewItemEventArgs = new DataGridItemEventArgs( this, m_currentAddItem ); @@ -3090,7 +2223,9 @@ namespace Xceed.Wpf.DataGrid this.QueueOperationForAddNew = false; if( m_currentAddItem != null ) + { this.CancelNew(); + } throw; } @@ -3116,8 +2251,7 @@ namespace Xceed.Wpf.DataGrid try { - DataGridCommittingNewItemEventArgs committingNewItemEventArgs = - new DataGridCommittingNewItemEventArgs( this, m_currentAddItem, false ); + DataGridCommittingNewItemEventArgs committingNewItemEventArgs = new DataGridCommittingNewItemEventArgs( this, m_currentAddItem, false ); this.RootDataGridCollectionViewBase.OnCommittingNewItem( committingNewItemEventArgs ); @@ -3135,10 +2269,8 @@ namespace Xceed.Wpf.DataGrid int addItemPosition = m_currentAddItemPosition; ItemsSourceHelper.EndNewDataItem( this.Enumeration, null, m_currentAddItem, ref addItemPosition ); - addOperationToNotifyIfNotAlreadyQueued = new DeferredOperation( - DeferredOperation.DeferredOperationAction.Add, - addItemPosition + 1, addItemPosition, - new object[] { m_currentAddItem } ); + addOperationToNotifyIfNotAlreadyQueued = new DeferredOperation( DeferredOperation.DeferredOperationAction.Add, addItemPosition + 1, + addItemPosition, new object[] { m_currentAddItem } ); } else { @@ -3151,10 +2283,8 @@ namespace Xceed.Wpf.DataGrid if( committingNewItemEventArgs.Index >= committingNewItemEventArgs.NewCount ) throw new InvalidOperationException( "The index at which the new item was inserted was greater than the new item count." ); - addOperationToNotifyIfNotAlreadyQueued = new DeferredOperation( - DeferredOperation.DeferredOperationAction.Add, - committingNewItemEventArgs.NewCount, committingNewItemEventArgs.Index, - new object[] { m_currentAddItem } ); + addOperationToNotifyIfNotAlreadyQueued = new DeferredOperation( DeferredOperation.DeferredOperationAction.Add, committingNewItemEventArgs.NewCount, + committingNewItemEventArgs.Index, new object[] { m_currentAddItem } ); } this.SetCurrentAddNew( null, -1 ); @@ -3188,8 +2318,7 @@ namespace Xceed.Wpf.DataGrid { Debug.Assert( !this.IsSourceSupportingChangeNotification ); - // No pending operation was in m_deferredAddNewOperationManager, - // so the list have not trigger notification for the new item added. + // No pending operation was in m_deferredAddNewOperationManager, so the list has not trigger notification for the new item added. // We will, in that case, raise the notification ourself. this.ExecuteOrQueueSourceItemOperation( addOperationToNotifyIfNotAlreadyQueued ); } @@ -3219,11 +2348,7 @@ namespace Xceed.Wpf.DataGrid if( !this.HasSource ) throw new InvalidOperationException( "The CancelingNewItem event must be handled when not using an underlying data source." ); - ItemsSourceHelper.CancelNewDataItem( - this.Enumeration, - null, - m_currentAddItem, - m_currentAddItemPosition ); + ItemsSourceHelper.CancelNewDataItem( this.Enumeration, null, m_currentAddItem, m_currentAddItemPosition ); } this.SetCurrentAddNew( null, -1 ); @@ -3270,7 +2395,7 @@ namespace Xceed.Wpf.DataGrid this.CommitEdit(); - DataGridItemCancelEventArgs itemCancelEventArgs = new DataGridItemCancelEventArgs( this, item, false ); + var itemCancelEventArgs = new DataGridItemCancelEventArgs( this, item, false ); m_rootDataGridCollectionViewBase.OnBeginningEdit( itemCancelEventArgs ); if( itemCancelEventArgs.Cancel ) @@ -3285,20 +2410,18 @@ namespace Xceed.Wpf.DataGrid if( !beginEditCalled ) { - DataGridItemPropertyCollection itemProperties = this.ItemProperties; - int count = itemProperties.Count; - m_oldValuesBeforeEdition = new object[ count ]; + var itemProperties = this.ItemProperties; + m_oldValuesBeforeEdition = new Dictionary( itemProperties.Count ); - for( int i = 0; i < count; i++ ) + foreach( var itemProperty in itemProperties ) { - m_oldValuesBeforeEdition[ i ] = itemProperties[ i ].GetValue( item ); + m_oldValuesBeforeEdition[ itemProperty ] = ItemsSourceHelper.GetValueFromItemProperty( itemProperty, item ); } } } m_currentEditItem = item; - DataGridItemEventArgs itemEventArgs = new DataGridItemEventArgs( this, item ); - m_rootDataGridCollectionViewBase.OnEditBegun( itemEventArgs ); + m_rootDataGridCollectionViewBase.OnEditBegun( new DataGridItemEventArgs( this, item ) ); } public virtual void CommitEdit() @@ -3306,7 +2429,7 @@ namespace Xceed.Wpf.DataGrid if( m_currentEditItem == null ) return; - DataGridItemCancelEventArgs itemCancelEventArgs = new DataGridItemCancelEventArgs( this, m_currentEditItem, false ); + var itemCancelEventArgs = new DataGridItemCancelEventArgs( this, m_currentEditItem, false ); m_rootDataGridCollectionViewBase.OnCommittingEdit( itemCancelEventArgs ); if( itemCancelEventArgs.Cancel ) @@ -3322,20 +2445,13 @@ namespace Xceed.Wpf.DataGrid m_oldValuesBeforeEdition = null; } - DataGridItemEventArgs itemEventArgs = new DataGridItemEventArgs( this, m_currentEditItem ); - int index = this.IndexOfSourceItem( m_currentEditItem ); - Debug.Assert( index != -1 ); + var itemEventArgs = new DataGridItemEventArgs( this, m_currentEditItem ); + var index = this.IndexOfSourceItem( m_currentEditItem ); - object[] items = new object[] { m_currentEditItem }; + var items = new object[] { m_currentEditItem }; m_currentEditItem = null; - // Only execute or queue a replace operation if the item is not already queued for a remove operation. - if( !this.DeferredOperationManager.ContainsItemForRemoveOperation( items[ 0 ] ) ) - { - this.ExecuteOrQueueSourceItemOperation( new DeferredOperation( - DeferredOperation.DeferredOperationAction.Replace, - -1, index, items, index, items ) ); - } + this.ExecuteOrQueueSourceItemOperation( new DeferredOperation( DeferredOperation.DeferredOperationAction.Replace, -1, index, items, index, items ) ); m_rootDataGridCollectionViewBase.OnEditCommitted( itemEventArgs ); } @@ -3356,7 +2472,7 @@ namespace Xceed.Wpf.DataGrid if( m_currentEditItem == null ) return; - DataGridItemHandledEventArgs itemHandleEventArgs = new DataGridItemHandledEventArgs( this, m_currentEditItem ); + var itemHandleEventArgs = new DataGridItemHandledEventArgs( this, m_currentEditItem ); m_rootDataGridCollectionViewBase.OnCancelingEdit( itemHandleEventArgs ); if( itemHandleEventArgs.Handled != this.ItemEditionIsManuallyHandled ) @@ -3367,34 +2483,30 @@ namespace Xceed.Wpf.DataGrid bool cancelEditCalled; this.CancelEditInternal( m_currentEditItem, out cancelEditCalled ); - DataGridItemPropertyCollection itemProperties = this.ItemProperties; - int count = itemProperties.Count; + var itemProperties = this.ItemProperties; - if( ( !cancelEditCalled ) && ( count > 0 ) ) + if( ( !cancelEditCalled ) && ( itemProperties.Count > 0 ) ) { itemProperties.SuspendUnboundItemPropertyChanged( m_currentEditItem ); try { - for( int i = 0; i < count; i++ ) + foreach( var itemProperty in itemProperties ) { - DataGridItemPropertyBase itemProperty = itemProperties[ i ]; + var readOnly = ( ( m_currentEditItem == m_currentAddItem ) && itemProperty.OverrideReadOnlyForInsertion.HasValue && itemProperty.OverrideReadOnlyForInsertion.Value ) + ? false + : itemProperty.IsReadOnly; - bool readOnly = ( ( m_currentEditItem == m_currentAddItem ) - && itemProperty.OverrideReadOnlyForInsertion.HasValue - && itemProperty.OverrideReadOnlyForInsertion.Value ) - ? false : itemProperty.IsReadOnly; + if( readOnly ) + continue; - if( !readOnly ) + try { - try - { - itemProperty.SetValue( m_currentEditItem, m_oldValuesBeforeEdition[ i ] ); - } - catch - { - // Swallow any Exception, setting a property to is old value should not throw. - } + ItemsSourceHelper.SetValueForItemProperty( itemProperty, m_currentEditItem, m_oldValuesBeforeEdition[ itemProperty ] ); + } + catch + { + // Swallow any Exception, setting a property to is old value should not throw. } } } @@ -3405,7 +2517,7 @@ namespace Xceed.Wpf.DataGrid } } - DataGridItemEventArgs itemEventArgs = new DataGridItemEventArgs( this, m_currentEditItem ); + var itemEventArgs = new DataGridItemEventArgs( this, m_currentEditItem ); m_currentEditItem = null; m_rootDataGridCollectionViewBase.OnEditCanceled( itemEventArgs ); } @@ -3515,7 +2627,7 @@ namespace Xceed.Wpf.DataGrid private NewItemPlaceholderPosition m_newItemPlaceholderPosition = NewItemPlaceholderPosition.None; - #endregion IEditableCollectionView + #endregion #region IItemProperties Members @@ -3534,22 +2646,8 @@ namespace Xceed.Wpf.DataGrid internal virtual List GetItemPropertyInfos() { - List itemPropertyInfos = new List(); - - int itemPropertyCount = m_itemProperties.Count; - - for( int i = 0; i < itemPropertyCount; i++ ) - { - DataGridItemPropertyBase dataGridItemPropertyBase = m_itemProperties[ i ]; - - itemPropertyInfos.Add( - new ItemPropertyInfo( - dataGridItemPropertyBase.Name, - dataGridItemPropertyBase.DataType, - dataGridItemPropertyBase.GetPropertyDescriptorForBinding() ) ); - } - - return itemPropertyInfos; + return ( from item in m_itemProperties + select new ItemPropertyInfo( item.Name, item.DataType, item.GetPropertyDescriptorForBinding() ) ).ToList(); } #endregion @@ -3561,43 +2659,37 @@ namespace Xceed.Wpf.DataGrid private int m_deferRefreshCount; - private DataGridCollectionViewBase m_rootDataGridCollectionViewBase; + private readonly DataGridCollectionViewBase m_rootDataGridCollectionViewBase; private Type m_itemType; private Type m_desiredItemType; private object m_modelSource; private IEnumerable m_enumeration; - private INotifyCollectionChanged m_notifyCollectionChanged; - private DataTable m_dataTable; private int m_currentPosition; private object m_currentItem; private int m_deferCurrencyEventCount; private object m_currentEditItem; - private object[] m_oldValuesBeforeEdition; + private Dictionary m_oldValuesBeforeEdition; private object m_currentAddItem; private int m_currentAddItemPosition = -1; - private AutoFilterMode m_autoFilterMode = AutoFilterMode.None; private DistinctValuesConstraint m_distinctValuesConstraint = DistinctValuesConstraint.All; private DistinctValuesUpdateMode m_distinctValueUpdateMode = DistinctValuesUpdateMode.Manual; - private FilterCriteriaMode m_filterCriteriaMode = FilterCriteriaMode.And; private List m_filteredItemProperties; private ReadOnlyCollection m_readOnlyFilteredItemProperties; private DataGridDetailDescription m_parentDetailDescription; - private DataGridItemPropertyCollection m_itemProperties; - private List m_defaultItemProperties; - - private DataGridDetailDescriptionCollection m_dataGridDetailDescriptions; - private List m_defaultDetailDescriptions; + private readonly DataGridItemPropertyCollection m_itemProperties; private DataGridSortDescriptionCollection m_sortDescriptions; private ObservableCollection m_groupDescriptions; + private readonly DataGridDetailDescriptionCollection m_detailDescriptions; + private readonly PropertyDescriptionRouteDictionary m_defaultPropertyDescriptions; private CollectionViewGroup m_rootGroup; @@ -3605,25 +2697,24 @@ namespace Xceed.Wpf.DataGrid // Containing a DataGridItemProperty key, ObservableCollection values map private DistinctValuesDictionary m_distinctValues; - private ReadOnlyDictionary m_autoFilterValues; - private ObservableCollection m_autoFilteredDataGridItemProperties; private DataGridItemPropertyBase m_excludedItemPropertyFromDistinctValueCalculation; [Flags] private enum DataGridCollectionViewBaseFlags { - Loaded = 1, - ItemPropertiesCreated = 2, - Refreshing = 4, - QueueOperationForAddNew = 16, - IsRefreshingDistinctValues = 32, - IsCurrentAfterLast = 64, - IsCurrentBeforeFirst = 128, - CreatingNewItemIsManuallyHandled = 256, - ItemEditionIsManuallyHandled = 512, - AutoCreateItemProperties = 1024, - AutoCreateDetailDescriptions = 2048, - AutoCreateForeignKeyDescriptions = 4096, + Loaded = 1 << 0, + Refreshing = 1 << 1, + QueueOperationForAddNew = 1 << 2, + IsRefreshingDistinctValues = 1 << 3, + IsCurrentAfterLast = 1 << 4, + IsCurrentBeforeFirst = 1 << 5, + CreatingNewItemIsManuallyHandled = 1 << 6, + ItemEditionIsManuallyHandled = 1 << 7, + AutoCreateItemProperties = 1 << 8, + AutoCreateDetailDescriptions = 1 << 9, + AutoCreateForeignKeyDescriptions = 1 << 10, + DefaultItemPropertiesInitialized = 1 << 11, + DefaultPropertyDescriptionsCreated = 1 << 12, } private sealed class DeferRefreshHelper : IDisposable @@ -3643,10 +2734,9 @@ namespace Xceed.Wpf.DataGrid private void Dispose( bool disposing ) { - var collectionView = m_collectionView; - // Prevent this method from being invoked more than once by the same IDisposable. - if( Interlocked.CompareExchange( ref m_collectionView, null, collectionView ) == null ) + var collectionView = Interlocked.Exchange( ref m_collectionView, null ); + if( collectionView == null ) return; if( collectionView.CheckAccess() ) @@ -3725,10 +2815,9 @@ namespace Xceed.Wpf.DataGrid private void Dispose( bool disposing ) { - var collectionView = m_collectionView; - // Prevent this method from being invoked more than once by the same IDisposable. - if( Interlocked.CompareExchange( ref m_collectionView, null, collectionView ) == null ) + var collectionView = Interlocked.Exchange( ref m_collectionView, null ); + if( collectionView == null ) return; if( collectionView.CheckAccess() ) diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewBaseDataProvider.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewBaseDataProvider.cs index b0a3e4bb..93604b4e 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewBaseDataProvider.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewBaseDataProvider.cs @@ -15,19 +15,15 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Data; +using System.Diagnostics; using System.Windows; +using System.Windows.Data; using System.Windows.Threading; namespace Xceed.Wpf.DataGrid { internal abstract class DataGridCollectionViewBaseDataProvider : DataSourceProvider, IWeakEventListener { - #region CONSTRUCTORS - internal DataGridCollectionViewBaseDataProvider( DataGridCollectionViewSourceBase parentSource ) : base() { @@ -37,38 +33,33 @@ namespace Xceed.Wpf.DataGrid m_parentSource = parentSource; } - #endregion CONSTRUCTORS - - #region IWeakEventListener Members + #region CurrentView Property - bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) + public DataGridCollectionViewBase CurrentView { - if( managerType == typeof( DataChangedEventManager ) ) + get { - this.Refresh(); - return true; + return m_currentView; } - - return false; } + private DataGridCollectionViewBase m_currentView; + #endregion - #region CurrentView Property + #region ParentSource Internal Property - public DataGridCollectionViewBase CurrentView + internal DataGridCollectionViewSourceBase ParentSource { get { - return m_currentView; + return m_parentSource; } } - private DataGridCollectionViewBase m_currentView; + private readonly DataGridCollectionViewSourceBase m_parentSource; - #endregion CurrentView Property - - #region PUBLIC METHODS + #endregion public void DelayRefresh( Dispatcher dispatcher, DispatcherPriority priority ) { @@ -77,7 +68,7 @@ namespace Xceed.Wpf.DataGrid return; // Call Refresh on the dispatcher with the specified priority. - DispatcherOperation operation = dispatcher.BeginInvoke( + var operation = dispatcher.BeginInvoke( priority, new Action( delegate { @@ -94,13 +85,9 @@ namespace Xceed.Wpf.DataGrid } } - #endregion PUBLIC METHODS - - #region PROTECTED METHODS - protected override void BeginQuery() { - Exception queryException = null; + var queryException = default( Exception ); try { @@ -114,82 +101,79 @@ namespace Xceed.Wpf.DataGrid this.OnQueryFinished( m_currentView, queryException, null, null ); } - #endregion PROTECTED METHODS - - #region INTERNAL PROPERTIES - - internal DataGridCollectionViewSourceBase ParentSource - { - get - { - return m_parentSource; - } - } - - #endregion INTERNAL PROPERTIES - - #region PRIVATE METHODS - internal abstract DataGridCollectionViewBase EnsureDataGridCollectionViewBaseCore(); private void EnsureDataGridCollectionViewBase() { + var success = false; + try { - DataGridCollectionViewBase view = this.EnsureDataGridCollectionViewBaseCore(); - - if( view == null ) - { - if( m_currentView != null ) - { - m_currentView.ParentCollectionViewSourceBase = null; - m_currentView = null; - } - } - - if( m_currentView != view ) + var newView = this.EnsureDataGridCollectionViewBaseCore(); + if( newView != m_currentView ) { - DataGridCollectionViewBase oldView = m_currentView; + this.ClearView(); - m_currentView = view; + m_currentView = newView; - if( ( oldView != null ) && ( oldView.ItemProperties != null ) ) + if( m_currentView != null ) { - // Ensure to unregister the ItemsProperties collection from - // events of the ItemProperties it contains to avoid memory leaks. - // The ItemProperties are reused when a new DataGridCollectionViewBase - // is generated by the DataGridCollectionViewBaseDataProvider and - // the ItemProperties collection of this new DataGridCollectionViewBase - // will also register to those events. - // We can safely unregister from those here wince the old - // DataGridCollectionViewBase will not be reused anywhere else. - oldView.ItemProperties.UnregisterDataGridItemPropertiesEvents(); + m_currentView.ParentCollectionViewSourceBase = m_parentSource; } } - if( m_currentView != null ) - m_currentView.ParentCollectionViewSourceBase = m_parentSource; + Debug.Assert( ( m_currentView == null ) || ( m_currentView.ParentCollectionViewSourceBase == m_parentSource ) ); + + success = true; } - catch + finally { - m_currentView.ParentCollectionViewSourceBase = null; - m_currentView = null; - throw; + if( !success ) + { + this.ClearView(); + } } } + private void ClearView() + { + if( m_currentView == null ) + return; + + var view = m_currentView; + m_currentView = null; + + view.Dispose(); + } + private void OnDelayedRefreshCompleted( object sender, EventArgs e ) { m_delayedRefreshPending = false; } - #endregion PRIVATE METHODS + #region IWeakEventListener Members - #region PRIVATE FIELDS + bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) + { + return this.OnReceiveWeakEvent( managerType, sender, e ); + } - private bool m_delayedRefreshPending; - private DataGridCollectionViewSourceBase m_parentSource; + protected virtual bool OnReceiveWeakEvent( Type managerType, object sender, EventArgs e ) + { + if( managerType == typeof( DataChangedEventManager ) ) + { + this.Refresh(); + } + else + { + return false; + } + + return true; + } #endregion + + private bool m_delayedRefreshPending; } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewGroup.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewGroup.cs index 5a6ae74f..aeb74be4 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewGroup.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewGroup.cs @@ -25,7 +25,6 @@ using System.Globalization; using System.Reflection; using System.Reflection.Emit; using System.Windows.Data; -using Xceed.Wpf.DataGrid.Stats; namespace Xceed.Wpf.DataGrid { @@ -41,6 +40,7 @@ namespace Xceed.Wpf.DataGrid { m_nextSubGroupUnsortedIndex = template.m_nextSubGroupUnsortedIndex; m_subGroupBy = template.m_subGroupBy; + m_groupByName = template.GroupByName; } private DataGridCollectionViewGroup( object name, DataGridCollectionViewGroup parent, int unsortedIndex ) @@ -109,36 +109,44 @@ namespace Xceed.Wpf.DataGrid #endregion - #region SubGroupBy Property + #region GroupByName Property - internal GroupDescription SubGroupBy + internal string GroupByName { get { - return m_subGroupBy; + return m_groupByName; + } + set + { + m_groupByName = value; } } + private string m_groupByName; + #endregion - #region Parent Property + #region SubGroupBy Property - internal DataGridCollectionViewGroup Parent + internal GroupDescription SubGroupBy { get { - return m_parent; + return m_subGroupBy; } } #endregion - #region CalculateAllStats Property + #region Parent Property - internal bool CalculateAllStats + internal DataGridCollectionViewGroup Parent { - get; - set; + get + { + return m_parent; + } } #endregion @@ -219,20 +227,23 @@ namespace Xceed.Wpf.DataGrid internal int GetFirstRawItemGlobalSortedIndex() { - int index = 0; - DataGridCollectionViewGroup group = this; - DataGridCollectionViewGroup parent = this.Parent; - DataGridCollectionViewGroup currentGroup = null; + var index = 0; + var group = this; + var parent = this.Parent; + var currentGroup = default( DataGridCollectionViewGroup ); while( parent != null ) { - foreach( object value in parent.ProtectedItems ) + var items = parent.ProtectedItems; + var count = items.Count; + + for( int i = 0; i < count; i++ ) { + var value = items[ i ]; if( value == group ) break; currentGroup = value as DataGridCollectionViewGroup; - index += currentGroup.GlobalRawItemCount; } @@ -297,31 +308,30 @@ namespace Xceed.Wpf.DataGrid } internal void SortItems( - SortDescriptionInfo[] sortDescriptionInfos, + IList sortDescriptionInfos, List groupSortComparers, int level, List globalRawItems, DataGridCollectionViewGroup newSortedGroup ) { - int itemCount = this.ProtectedItemCount; - + var itemCount = this.ProtectedItemCount; if( itemCount == 0 ) return; if( this.IsBottomLevel ) { - int[] indexes; - indexes = new int[ itemCount + 1 ]; + var indexes = new int[ itemCount + 1 ]; + for( int i = 0; i < itemCount; i++ ) { indexes[ i ] = m_sortedRawItems[ i ].Index; } // "Weak heap sort" sort array[0..NUM_ELEMENTS-1] to array[1..NUM_ELEMENTS] - DataGridCollectionViewSort collectionViewSort = new DataGridCollectionViewSort( indexes, sortDescriptionInfos ); + var collectionViewSort = new DataGridCollectionViewSort( indexes, sortDescriptionInfos ); collectionViewSort.Sort( itemCount ); - int index = 0; + var index = 0; for( int i = 1; i <= itemCount; i++ ) { @@ -331,18 +341,18 @@ namespace Xceed.Wpf.DataGrid } else { - int[] indexes; - indexes = new int[ itemCount + 1 ]; + var indexes = new int[ itemCount + 1 ]; + for( int i = 0; i < itemCount; i++ ) { indexes[ i ] = i; } - DataGridCollectionViewGroup[] subGroupsArray = new DataGridCollectionViewGroup[ itemCount ]; + var subGroupsArray = new DataGridCollectionViewGroup[ itemCount ]; m_subGroups.Values.CopyTo( subGroupsArray, 0 ); // "Weak heap sort" sort array[0..NUM_ELEMENTS-1] to array[1..NUM_ELEMENTS] - DataGridCollectionViewGroupSort collectionViewSort = new DataGridCollectionViewGroupSort( indexes, groupSortComparers[ level ], subGroupsArray ); + var collectionViewSort = new DataGridCollectionViewGroupSort( indexes, groupSortComparers[ level ], subGroupsArray ); collectionViewSort.Sort( itemCount ); int index = 0; @@ -604,71 +614,6 @@ namespace Xceed.Wpf.DataGrid return ~low; } - - internal object GetStatFunctionValue( string propertyName ) - { - DataGridCollectionView view = this.GetCollectionView(); - - Debug.Assert( view != null ); - - if( view == null ) - return null; - - StatFunction statFunction = view.StatFunctions[ propertyName ]; - - Debug.Assert( view != null ); - - if( statFunction == null ) - return null; - - return this.GetStatFunctionResult( statFunction, view ).Value; - } - - internal StatResult GetStatFunctionResult( StatFunction statFunction, DataGridCollectionView view ) - { - StatResult result; - - if( !m_statFunctionValues.TryGetValue( statFunction, out result ) ) - { - result = null; - m_statFunctionValues[ statFunction ] = result; - } - - return result; - } - - // This clears the value of all the previously calculated StatFunction Results for this group. - internal void ClearStatFunctionsResult() - { - m_statFunctionValues.Clear(); - } - - internal void InvokeStatFunctionsPropertyChanged( DataGridCollectionView collectionView ) - { - if( this.HasPropertyChangedListeners ) - { - if( collectionView.CalculateChangedPropertyStatsOnly && !this.CalculateAllStats ) - { - foreach( StatFunction statFunction in collectionView.InvalidatedStatFunctions ) - { - { - this.OnPropertyChanged( new PropertyChangedEventArgs( statFunction.ResultPropertyName ) ); - } - } - } - else - { - foreach( PropertyDescriptor statFunctionPropertyDescriptor in collectionView.GetStatFunctionProperties() ) - { - this.OnPropertyChanged( new PropertyChangedEventArgs( statFunctionPropertyDescriptor.Name ) ); - } - } - } - - this.CalculateAllStats = false; - } - - private int BinarySearchGroup( DataGridCollectionViewGroup value, IComparer comparer ) { if( comparer == null ) @@ -731,7 +676,13 @@ namespace Xceed.Wpf.DataGrid List groupSortComparers ) { // If sortComparers is null, we are in massive group creation, no order check. - DataGridCollectionViewGroup group = new DataGridCollectionViewGroup( groupName, this, m_nextSubGroupUnsortedIndex ); + var group = new DataGridCollectionViewGroup( groupName, this, m_nextSubGroupUnsortedIndex ); + + var dataGridGroupDescription = groupByList[ level ] as DataGridGroupDescription; + if( dataGridGroupDescription != null ) + { + group.GroupByName = dataGridGroupDescription.PropertyName; + } unchecked { @@ -866,10 +817,8 @@ namespace Xceed.Wpf.DataGrid return TypeDescriptor.GetProperties( typeof( DataGridCollectionViewGroup ) ); PropertyDescriptorCollection classProperties = TypeDescriptor.GetProperties( typeof( DataGridCollectionViewGroup ) ); - PropertyDescriptorCollection statProperties = view.GetStatFunctionProperties(); - PropertyDescriptor[] properties = new PropertyDescriptor[ classProperties.Count + statProperties.Count ]; + PropertyDescriptor[] properties = new PropertyDescriptor[ classProperties.Count ]; classProperties.CopyTo( properties, 0 ); - statProperties.CopyTo( properties, classProperties.Count ); m_classProperties = new PropertyDescriptorCollection( properties ); } @@ -881,12 +830,6 @@ namespace Xceed.Wpf.DataGrid PropertyDescriptorCollection props = TypeDescriptor.GetProperties( this, attributes ); DataGridCollectionView view = this.GetCollectionView(); - if( view != null ) - { - foreach( PropertyDescriptor property in view.GetStatFunctionProperties() ) - props.Add( property ); - } - return props; } } @@ -939,7 +882,6 @@ namespace Xceed.Wpf.DataGrid #endregion private PropertyDescriptorCollection m_classProperties; - private readonly Dictionary m_statFunctionValues = new Dictionary( StatFunctionComparer.Default ); protected int m_globalRawItemCount; protected readonly List m_sortedRawItems; @@ -1022,7 +964,7 @@ namespace Xceed.Wpf.DataGrid var storage = ( s_getItems != null ) ? s_getItems.Invoke( source ) : null; if( storage == null ) - throw new InvalidOperationException( "TODODOC: Unable to retrieve the ObservableCollection<>'s items storage." ); + throw new InvalidOperationException( "Unable to retrieve the ObservableCollection<>'s items storage." ); return storage; } @@ -1034,7 +976,7 @@ namespace Xceed.Wpf.DataGrid var collectionChanged = ( s_collectionChanged != null ) ? s_collectionChanged.Invoke( source ) : null; if( collectionChanged == null ) - throw new InvalidOperationException( "TODODOC: Unable to retrieve the ObservableCollection<>'s collection change method." ); + throw new InvalidOperationException( "Unable to retrieve the ObservableCollection<>'s collection change method." ); return collectionChanged; } @@ -1043,11 +985,11 @@ namespace Xceed.Wpf.DataGrid { var propertyInfo = typeof( ObservableCollection ).GetProperty( "Items", BindingFlags.Instance | BindingFlags.NonPublic, null, typeof( IList ), new Type[ 0 ], null ); if( ( propertyInfo == null ) || !propertyInfo.CanRead ) - throw new InvalidOperationException( "TODODOC: Unable to retrieve the ObservableCollection<>.Items property." ); + throw new InvalidOperationException( "Unable to retrieve the ObservableCollection<>.Items property." ); var methodInfo = propertyInfo.GetGetMethod( true ); if( ( methodInfo == null ) || !ObservableCollectionHelper.HasCallingConvention( methodInfo.CallingConvention, CallingConventions.HasThis ) ) - throw new InvalidOperationException( "TODODOC: Unable to retrieve the ObservableCollection<>.Items property." ); + throw new InvalidOperationException( "Unable to retrieve the ObservableCollection<>.Items property." ); var methodBuilder = typeBuilder.DefineMethod( ObservableCollectionHelper.GetItemsMethodName, @@ -1071,11 +1013,11 @@ namespace Xceed.Wpf.DataGrid { var methodInfo = typeof( ObservableCollection ).GetMethod( "OnCollectionChanged", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof( NotifyCollectionChangedEventArgs ) }, null ); if( ( methodInfo == null ) || methodInfo.IsPrivate || !ObservableCollectionHelper.HasCallingConvention( methodInfo.CallingConvention, CallingConventions.HasThis ) ) - throw new InvalidOperationException( "TODODOC: Unable to retrieve the ObservableCollection<>.OnCollectionChanged method." ); + throw new InvalidOperationException( "Unable to retrieve the ObservableCollection<>.OnCollectionChanged method." ); var constructorInfo = typeof( Action ).GetConstructor( new Type[] { typeof( object ), typeof( IntPtr ) } ); if( ( constructorInfo == null ) || constructorInfo.IsPrivate || !ObservableCollectionHelper.HasCallingConvention( constructorInfo.CallingConvention, CallingConventions.HasThis ) ) - throw new InvalidOperationException( "TODODOC: Unable to retrieve the Action<>'s constructor." ); + throw new InvalidOperationException( "Unable to retrieve the Action<>'s constructor." ); var methodBuilder = typeBuilder.DefineMethod( ObservableCollectionHelper.GetCollectionChangedMethodName, diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewGroupRoot.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewGroupRoot.cs index 56b01404..55dde31d 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewGroupRoot.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewGroupRoot.cs @@ -39,30 +39,30 @@ namespace Xceed.Wpf.DataGrid return m_parentCollectionView; } - internal void SortRootRawItems( SortDescriptionInfo[] sortDescriptionInfos, List globalRawItems ) + internal void SortRootRawItems( IList sortDescriptionInfos, List globalRawItems ) { Debug.Assert( this.IsBottomLevel ); - int itemCount = m_sortedRawItems.Count; + var itemCount = m_sortedRawItems.Count; if( itemCount == 0 ) return; - int[] indexes; - indexes = new int[ itemCount + 1 ]; + var indexes = new int[ itemCount + 1 ]; + for( int i = 0; i < itemCount; i++ ) { indexes[ i ] = m_sortedRawItems[ i ].Index; } // "Weak heap sort" sort array[0..NUM_ELEMENTS-1] to array[1..NUM_ELEMENTS] - DataGridCollectionViewSort collectionViewSort = new DataGridCollectionViewSort( indexes, sortDescriptionInfos ); + var collectionViewSort = new DataGridCollectionViewSort( indexes, sortDescriptionInfos ); collectionViewSort.Sort( itemCount ); - int index = 0; + var index = 0; for( int i = 1; i <= itemCount; i++ ) { - RawItem newRawItem = globalRawItems[ indexes[ i ] ]; + var newRawItem = globalRawItems[ indexes[ i ] ]; newRawItem.SetSortedIndex( index ); m_sortedRawItems[ index ] = newRawItem; index++; diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewSort.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewSort.cs index 180fcdfa..ba3e1704 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewSort.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewSort.cs @@ -14,20 +14,15 @@ ***********************************************************************************/ -using System; -using System.ComponentModel; using System.Collections.Generic; -using System.Text; - +using System.ComponentModel; using Xceed.Utils.Collections; -using System.Collections; -using Xceed.Utils.Data; namespace Xceed.Wpf.DataGrid { internal class DataGridCollectionViewSort : IndexWeakHeapSort { - public DataGridCollectionViewSort( int[] dataIndexArray, SortDescriptionInfo[] sortDescriptionInfos ) + public DataGridCollectionViewSort( int[] dataIndexArray, IList sortDescriptionInfos ) : base( dataIndexArray ) { m_sortDescriptionInfos = sortDescriptionInfos; @@ -35,41 +30,25 @@ namespace Xceed.Wpf.DataGrid public override int Compare( int xDataIndex, int yDataIndex ) { - ListSortDirection lastSortDirection = ListSortDirection.Ascending; + var lastSortDirection = ListSortDirection.Ascending; if( m_sortDescriptionInfos != null ) { - int result = 0; - int count = m_sortDescriptionInfos.Length; - - for( int i = 0; i < count; i++ ) + foreach( var sortDescriptionInfo in m_sortDescriptionInfos ) { - SortDescriptionInfo sortDescriptionInfo = m_sortDescriptionInfos[ i ]; - lastSortDirection = sortDescriptionInfo.SortDirection; if( sortDescriptionInfo.Property == null ) continue; - IComparer sortComparer = sortDescriptionInfo.SortComparer; - DataStore dataStore = sortDescriptionInfo.DataStore; - - if( sortComparer != null ) - { - result = sortComparer.Compare( dataStore.GetData( xDataIndex ), dataStore.GetData( yDataIndex ) ); - } - else - { - result = dataStore.Compare( xDataIndex, yDataIndex ); - } - - if( result != 0 ) - { - if( lastSortDirection == ListSortDirection.Descending ) - result = -result; - - return result; - } + var sortComparer = sortDescriptionInfo.SortComparer; + var dataStore = sortDescriptionInfo.DataStore; + var compare = ( sortComparer != null ) + ? sortComparer.Compare( dataStore.GetData( xDataIndex ), dataStore.GetData( yDataIndex ) ) + : dataStore.Compare( xDataIndex, yDataIndex ); + + if( compare != 0 ) + return ( lastSortDirection == ListSortDirection.Descending ) ? -compare : compare; } } @@ -79,6 +58,6 @@ namespace Xceed.Wpf.DataGrid return xDataIndex - yDataIndex; } - private SortDescriptionInfo[] m_sortDescriptionInfos; + private readonly IList m_sortDescriptionInfos; } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewSource.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewSource.cs index 195bb6db..0c88a205 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewSource.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewSource.cs @@ -20,7 +20,6 @@ using System.Collections.Specialized; using System.ComponentModel; using System.Windows; using System.Windows.Data; -using Xceed.Wpf.DataGrid.Stats; namespace Xceed.Wpf.DataGrid { @@ -38,8 +37,6 @@ namespace Xceed.Wpf.DataGrid public DataGridCollectionViewSource() : base() { - m_statFunctions = new StatFunctionCollection(); - m_statFunctions.CollectionChanged += new NotifyCollectionChangedEventHandler( this.ForwardedCollection_CollectionChanged ); } #endregion CONSTRUCTORS @@ -58,20 +55,6 @@ namespace Xceed.Wpf.DataGrid #endregion CollectionViewType Property - #region StatFunctions Property - - internal ObservableCollection StatFunctions - { - get - { - return m_statFunctions; - } - } - - private StatFunctionCollection m_statFunctions; - - #endregion StatFunctions Property - #region UpdateChangedPropertyStatsOnly Property internal bool UpdateChangedPropertyStatsOnly @@ -106,18 +89,7 @@ namespace Xceed.Wpf.DataGrid internal override void ApplyExtraPropertiesToView( DataGridCollectionViewBase currentView ) { - base.ApplyExtraPropertiesToView( currentView ); - - DataGridCollectionView dataGridCollectionView = currentView as DataGridCollectionView; - - dataGridCollectionView.StatFunctions.Clear(); - - foreach( var statFunction in m_statFunctions ) - { - dataGridCollectionView.StatFunctions.Add( statFunction ); - } - - dataGridCollectionView.UpdateChangedPropertyStatsOnly = this.UpdateChangedPropertyStatsOnly; + base.ApplyExtraPropertiesToView( currentView ); } #endregion INTERNAL METHODS diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewSourceBase.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewSourceBase.cs index 8900c0c6..3e74c516 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewSourceBase.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewSourceBase.cs @@ -15,21 +15,16 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Data; -using System.Windows; using System.Collections.ObjectModel; -using System.Globalization; using System.Collections.Specialized; +using System.Globalization; +using System.Windows; +using System.Windows.Data; namespace Xceed.Wpf.DataGrid { public abstract class DataGridCollectionViewSourceBase : CollectionViewSource { - #region CONSTRUCTORS - static DataGridCollectionViewSourceBase() { CollectionViewSource.SourceProperty.OverrideMetadata( @@ -41,8 +36,8 @@ namespace Xceed.Wpf.DataGrid } public DataGridCollectionViewSourceBase() - : base() { + m_itemProperties = new ObservableCollection(); m_itemProperties.CollectionChanged += new NotifyCollectionChangedEventHandler( this.ForwardedCollection_CollectionChanged ); m_dataGridDetailDescriptions = new DataGridDetailDescriptionCollection(); @@ -56,8 +51,6 @@ namespace Xceed.Wpf.DataGrid this.Culture = CultureInfo.InvariantCulture; } - #endregion CONSTRUCTORS - #region ItemProperties Property public ObservableCollection ItemProperties @@ -70,7 +63,7 @@ namespace Xceed.Wpf.DataGrid private ObservableCollection m_itemProperties; - #endregion ItemProperties Property + #endregion #region DetailDescriptions Property @@ -84,7 +77,7 @@ namespace Xceed.Wpf.DataGrid private ObservableCollection m_dataGridDetailDescriptions; - #endregion DetailDescriptions Property + #endregion #region ItemType Property @@ -107,7 +100,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion ItemType Property + #endregion #region CollectionViewType Property @@ -121,7 +114,7 @@ namespace Xceed.Wpf.DataGrid base.OnCollectionViewTypeChanged( oldCollectionViewType, newCollectionViewType ); } - #endregion CollectionViewType Property + #endregion #region AutoCreateItemProperties Property @@ -142,7 +135,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion AutoCreateItemProperties Property + #endregion #region AutoCreateDetailDescriptions Property @@ -163,28 +156,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion AutoCreateDetailDescriptions Property - - #region AutoFilterMode Property - - internal static readonly DependencyProperty AutoFilterModeProperty = DependencyProperty.Register( - "AutoFilterMode", typeof( AutoFilterMode ), typeof( DataGridCollectionViewSourceBase ), - new UIPropertyMetadata( AutoFilterMode.None, - new PropertyChangedCallback( DataGridCollectionViewSourceBase.OnDataGridCollectionViewSourceBaseDependencyPropertyChanged ) ) ); - - internal AutoFilterMode AutoFilterMode - { - get - { - return ( AutoFilterMode )this.GetValue( AutoFilterModeProperty ); - } - set - { - this.SetValue( AutoFilterModeProperty, value ); - } - } - - #endregion AutoFilterMode Property + #endregion #region DistinctValuesConstraints Property @@ -205,7 +177,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion DistinctValuesConstraints Property + #endregion #region DistinctValuesUpdateMode Property @@ -247,7 +219,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion DefaultCalculateDistinctValues Property + #endregion #region Culture Property @@ -272,39 +244,6 @@ namespace Xceed.Wpf.DataGrid } } - #endregion Culture Property - - #region FilterCriteriaMode Property - - public static readonly DependencyProperty FilterCriteriaModeProperty = DependencyProperty.Register( - "FilterCriteriaMode", typeof( FilterCriteriaMode ), typeof( DataGridCollectionViewSourceBase ), - new UIPropertyMetadata( FilterCriteriaMode.And, - new PropertyChangedCallback( DataGridCollectionViewSourceBase.OnDataGridCollectionViewSourceBaseDependencyPropertyChanged ) ) ); - - public FilterCriteriaMode FilterCriteriaMode - { - get - { - return ( FilterCriteriaMode )this.GetValue( DataGridCollectionViewSourceBase.FilterCriteriaModeProperty ); - } - set - { - this.SetValue( DataGridCollectionViewSourceBase.FilterCriteriaModeProperty, value ); - } - } - - #endregion FilterCriteriaMode Property - - #region AutoFilterValuesChanged Event - - internal event EventHandler AutoFilterValuesChanged; - - internal void OnAutoFilterValuesChanged( AutoFilterValuesChangedEventArgs e ) - { - if( this.AutoFilterValuesChanged != null ) - this.AutoFilterValuesChanged( this, e ); - } - #endregion #region DistinctValuesRefreshNeeded Event @@ -358,7 +297,7 @@ namespace Xceed.Wpf.DataGrid internal abstract DataGridCollectionViewBaseDataProvider CreateDataProvider(); - #endregion Source property + #endregion #region OriginalSource Property @@ -370,7 +309,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion OriginalSource Property + #endregion #region AutoCreateForeignKeyDescriptions Property @@ -395,6 +334,18 @@ namespace Xceed.Wpf.DataGrid #endregion + #region DataSourceProvider Internal Property + + internal DataGridCollectionViewBaseDataProvider DataSourceProvider + { + get + { + return m_dataSourceProvider; + } + } + + #endregion + #region EVENTS public event EventHandler InitializingNewItem; @@ -519,74 +470,33 @@ namespace Xceed.Wpf.DataGrid this.ItemRemoved( this, e ); } - #endregion EVENTS - - #region INTERNAL PROPERTIES - - internal DataGridCollectionViewBaseDataProvider DataSourceProvider - { - get - { - return m_dataSourceProvider; - } - } - - #endregion INTERNAL PROPERTIES - - #region INTERNAL METHODS + #endregion internal virtual void ApplyExtraPropertiesToView( DataGridCollectionViewBase currentView ) { - DataGridItemPropertyCollection currentViewItemProperties = currentView.ItemProperties; - int count = m_itemProperties.Count; + var currentViewItemProperties = currentView.ItemProperties; - for( int i = 0; i < count; i++ ) + foreach( var itemProperty in m_itemProperties ) { - DataGridItemPropertyBase itemProperty = m_itemProperties[ i ]; - int index = currentViewItemProperties.IndexOf( itemProperty.Name ); - - if( index == -1 ) - { - currentViewItemProperties.Add( itemProperty ); - } - else - { - currentViewItemProperties[ index ] = itemProperty; - } + currentViewItemProperties[ itemProperty.Name ] = itemProperty; } - count = currentView.ItemProperties.Count; - - bool defaultCalculateDistinctValues = this.DefaultCalculateDistinctValues; + var defaultCalculateDistinctValues = this.DefaultCalculateDistinctValues; - for( int i = 0; i < count; i++ ) + foreach( var itemProperty in currentViewItemProperties ) { - DataGridItemPropertyBase dataGridItemProperty = currentView.ItemProperties[ i ]; - // Set default value for CalculateDistinctValues if not explicitly set - if( !dataGridItemProperty.IsCalculateDistinctValuesInitialized ) - dataGridItemProperty.CalculateDistinctValues = defaultCalculateDistinctValues; + if( !itemProperty.IsCalculateDistinctValuesInitialized ) + { + itemProperty.CalculateDistinctValues = defaultCalculateDistinctValues; + } } - count = m_dataGridDetailDescriptions.Count; + var autoCreateForeignKeyDescriptions = this.AutoCreateForeignKeyDescriptions; - bool autoCreateForeignKeyDescriptions = this.AutoCreateForeignKeyDescriptions; - DataGridDetailDescriptionCollection currentViewDetailDescriptions = - currentView.DetailDescriptions; - - for( int i = 0; i < count; i++ ) + for( int i = 0; i < m_dataGridDetailDescriptions.Count; i++ ) { DataGridDetailDescription detailDescription = m_dataGridDetailDescriptions[ i ]; - int index = currentViewDetailDescriptions.IndexOf( detailDescription.RelationName ); - - if( index == -1 ) - { - currentViewDetailDescriptions.Add( detailDescription ); - } - else - { - currentViewDetailDescriptions[ index ] = detailDescription; - } // We assume we want to auto-create ForeignKeyDescriptions for DetailDescriptions // if this.AutoCreateForeignKeyDescriptions is true and it was auto-created @@ -595,17 +505,8 @@ namespace Xceed.Wpf.DataGrid detailDescription.AutoCreateForeignKeyDescriptions = autoCreateForeignKeyDescriptions; } } - - currentView.AutoFilterMode = this.AutoFilterMode; - currentView.DistinctValuesConstraint = this.DistinctValuesConstraint; - currentView.DistinctValuesUpdateMode = this.DistinctValuesUpdateMode; - currentView.FilterCriteriaMode = this.FilterCriteriaMode; } - #endregion INTERNAL METHODS - - #region PRIVATE METHODS - internal static void OnDataGridCollectionViewSourceBaseDependencyPropertyChanged( DependencyObject o, DependencyPropertyChangedEventArgs e ) { DataGridCollectionViewSourceBase source = o as DataGridCollectionViewSourceBase; @@ -639,13 +540,11 @@ namespace Xceed.Wpf.DataGrid base.Culture = base.Culture; } - #endregion PRIVATE METHODS - - #region PRIVATE FIELDS + #region Private Fields private DataGridCollectionViewBaseDataProvider m_dataSourceProvider; private object m_originalSource; - #endregion PRIVATE FIELDS + #endregion } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridDetailDescription.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridDetailDescription.cs index b74e6e1c..7595a6eb 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridDetailDescription.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridDetailDescription.cs @@ -15,47 +15,37 @@ ***********************************************************************************/ using System; +using System.Collections; using System.Collections.Generic; -using System.Text; using System.Collections.ObjectModel; +using System.Collections.Specialized; using System.ComponentModel; -using Xceed.Wpf.DataGrid.Stats; -using System.Data; -using System.Collections; using System.Diagnostics; +using System.Linq; using System.Windows; -using System.Windows.Data; using Xceed.Utils.Collections; -using System.Collections.Specialized; namespace Xceed.Wpf.DataGrid { internal abstract class DataGridDetailDescription : DependencyObject, IWeakEventListener { - #region Constructor - protected DataGridDetailDescription() { - m_detailDescriptions = new DataGridDetailDescriptionCollection(); - m_detailDescriptions.CollectionChanged += this.OnDetailDescriptionsCollectionChanged; - m_itemProperties = new DataGridItemPropertyCollection(); - m_itemProperties.CollectionChanged += this.OnItemPropertiesCollectionChanged; + m_detailDescriptions = new DataGridDetailDescriptionCollection(); + m_defaultPropertyDescriptions = new PropertyDescriptionRouteDictionary(); m_groupDescriptions = new GroupDescriptionCollection(); - m_sortDescriptions = new DataGridSortDescriptionCollection(); - m_statFunctions = new StatFunctionCollection(); - m_autoFilterValues = new ReadOnlyDictionary(); - m_autoFilteredItems = new ObservableCollection(); - m_registeredFieldNamesToAutoFilterValues = new Dictionary(); - m_registeredAutoFilterValuesToFieldNames = new Dictionary(); + m_sortDescriptions = new DataGridSortDescriptionCollection(); this.AutoCreateDetailDescriptions = true; this.AutoCreateItemProperties = true; this.DefaultCalculateDistinctValues = true; - } - #endregion + CollectionChangedEventManager.AddListener( m_itemProperties, this ); + InitializeItemPropertyEventManager.AddListener( m_itemProperties, this ); + CollectionChangedEventManager.AddListener( m_detailDescriptions, this ); + } #region RelationName Public Property @@ -74,6 +64,8 @@ namespace Xceed.Wpf.DataGrid } } + private string m_relationName; + #endregion #region Title Public Property @@ -90,6 +82,8 @@ namespace Xceed.Wpf.DataGrid } } + private object m_title; + #endregion #region TitleTemplate Public Property @@ -106,6 +100,8 @@ namespace Xceed.Wpf.DataGrid } } + private DataTemplate m_titleTemplate; + #endregion #region AutoCreateItemProperties Public Property @@ -156,34 +152,6 @@ namespace Xceed.Wpf.DataGrid #endregion - #region AutoFilterValues Public Property - - internal IDictionary AutoFilterValues - { - get - { - return m_autoFilterValues; - } - } - - #endregion - - #region AutoFilterMode Public Property - - internal AutoFilterMode AutoFilterMode - { - get - { - return m_autoFilterMode; - } - set - { - m_autoFilterMode = value; - } - } - - #endregion - #region DistinctValuesConstraint Public Property public DistinctValuesConstraint DistinctValuesConstraint @@ -198,25 +166,11 @@ namespace Xceed.Wpf.DataGrid } } - #endregion - - #region FilterCriteriaMode Public Property - - public FilterCriteriaMode FilterCriteriaMode - { - get - { - return m_filterCriteriaMode; - } - set - { - m_filterCriteriaMode = value; - } - } + private DistinctValuesConstraint m_distinctValuesConstraint = DistinctValuesConstraint.All; #endregion - #region ItemProperty Public Property + #region ItemProperties Public Property public DataGridItemPropertyCollection ItemProperties { @@ -226,6 +180,8 @@ namespace Xceed.Wpf.DataGrid } } + private readonly DataGridItemPropertyCollection m_itemProperties; + #endregion #region DefaultCalculateDistinctValues Public Property @@ -244,7 +200,7 @@ namespace Xceed.Wpf.DataGrid #endregion - #region DetailDesctiptions Public Property + #region DetailDescriptions Public Property public DataGridDetailDescriptionCollection DetailDescriptions { @@ -254,17 +210,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion - - #region StatFunctions Public Property - - internal StatFunctionCollection StatFunctions - { - get - { - return m_statFunctions; - } - } + private readonly DataGridDetailDescriptionCollection m_detailDescriptions; #endregion @@ -278,6 +224,8 @@ namespace Xceed.Wpf.DataGrid } } + private readonly GroupDescriptionCollection m_groupDescriptions; + #endregion #region SortDescriptions Public Propertiy @@ -290,6 +238,8 @@ namespace Xceed.Wpf.DataGrid } } + private readonly DataGridSortDescriptionCollection m_sortDescriptions; + #endregion #region AutoCreateItemPropertiesCompleted Internal Property @@ -324,18 +274,52 @@ namespace Xceed.Wpf.DataGrid #endregion - #region AutoFilteredItems Internal Property + #region DefaultItemPropertiesInitialized Internal Property - internal ObservableCollection AutoFilteredItems + internal bool DefaultItemPropertiesInitialized { get { - return m_autoFilteredItems; + return m_flags[ ( int )DataGridDetailDescriptionFlags.DefaultItemPropertiesInitialized ]; + } + set + { + m_flags[ ( int )DataGridDetailDescriptionFlags.DefaultItemPropertiesInitialized ] = value; } } #endregion + #region DefaultPropertyDescriptionsCreated Internal Property + + internal bool DefaultPropertyDescriptionsCreated + { + get + { + return m_flags[ ( int )DataGridDetailDescriptionFlags.DefaultPropertyDescriptionsCreated ]; + } + set + { + m_flags[ ( int )DataGridDetailDescriptionFlags.DefaultPropertyDescriptionsCreated ] = value; + } + } + + #endregion + + #region DefaultPropertyDescriptions Internal Property + + internal PropertyDescriptionRouteDictionary DefaultPropertyDescriptions + { + get + { + return m_defaultPropertyDescriptions; + } + } + + private readonly PropertyDescriptionRouteDictionary m_defaultPropertyDescriptions; + + #endregion + #region IsAutoCreated Internal Property internal bool IsAutoCreated @@ -384,36 +368,45 @@ namespace Xceed.Wpf.DataGrid #endregion - #region DataGridSortDescriptions Internal Property + #region ItemType Internal Property - internal DataGridSortDescriptionCollection DataGridSortDescriptions + internal Type ItemType { get { - return m_sortDescriptions; + return m_itemType; + } + set + { + if( value == m_itemType ) + return; + + m_itemType = value; } } + private Type m_itemType; //null + #endregion - #region AutoFilterValuesChanged Internal Property + #region DataGridSortDescriptions Internal Property - internal Action DetailDescriptionAutoFilterValuesChanged; + internal DataGridSortDescriptionCollection DataGridSortDescriptions + { + get + { + return m_sortDescriptions; + } + } #endregion - #region Protected Methods - protected internal virtual void Initialize( DataGridCollectionViewBase parentCollectionView ) { } protected internal abstract IEnumerable GetDetailsForParentItem( DataGridCollectionViewBase parentCollectionView, object parentItem ); - #endregion - - #region Internal Methods - internal void Seal() { this.InternalIsSealed = true; @@ -427,212 +420,88 @@ namespace Xceed.Wpf.DataGrid this.Initialize( parentCollectionView ); } - internal virtual void OnDetailDescriptionsCollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) + private void OnItemPropertiesCollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) { - // Set the AutoFilterValuesChanged event for each - // newly added DataGridDetailDescription added to - // collection - int newItemsCount = ( e.NewItems != null ) - ? e.NewItems.Count - : 0; - - int oldItemsCount = ( e.OldItems != null ) - ? e.OldItems.Count - : 0; + var removedItems = default( IEnumerable ); - for( int i = 0; i < oldItemsCount; i++ ) - { - DataGridDetailDescription description = e.OldItems[ i ] as DataGridDetailDescription; - - if( description == null ) - continue; - - description.UnregisterAllAutoFilterValuesChangedEvent(); - } - - for( int i = 0; i < newItemsCount; i++ ) - { - DataGridDetailDescription description = e.NewItems[ i ] as DataGridDetailDescription; - - if( description == null ) - continue; - - description.DetailDescriptionAutoFilterValuesChanged = this.RaiseDetailDescriptionAutoFilterValuesChangedEvent; - } - } - - internal virtual void OnItemPropertiesCollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) - { switch( e.Action ) { case NotifyCollectionChangedAction.Replace: - Debug.Assert( false, "The replace of an ItemProperty is not supported." ); + removedItems = e.OldItems.Cast(); break; - case NotifyCollectionChangedAction.Remove: - - int oldItemsCount = ( e.OldItems != null ) - ? e.OldItems.Count - : 0; - - for( int i = 0; i < oldItemsCount; i++ ) - { - DataGridItemPropertyBase dataGridItemProperty = e.OldItems[ i ] as DataGridItemPropertyBase; - Debug.Assert( dataGridItemProperty != null ); - this.UnregisterAutoFilterValuesChangedEvent( dataGridItemProperty.Name ); - } + case NotifyCollectionChangedAction.Remove: + removedItems = e.OldItems.Cast(); break; - case NotifyCollectionChangedAction.Reset: - this.UnregisterAllAutoFilterValuesChangedEvent(); - break; + case NotifyCollectionChangedAction.Reset: + throw new NotSupportedException(); } } - internal void RegisterAutoFilterValuesChangedEvent( string fieldName, INotifyCollectionChanged autoFilterValues ) - { - if( this.DetailDescriptionAutoFilterValuesChanged == null ) - return; - - if( m_registeredFieldNamesToAutoFilterValues.ContainsKey( fieldName ) ) - return; - - m_registeredFieldNamesToAutoFilterValues.Add( fieldName, autoFilterValues ); - m_registeredAutoFilterValuesToFieldNames.Add( autoFilterValues, fieldName ); - - CollectionChangedEventManager.AddListener( autoFilterValues, this ); - } - - internal void UnregisterAllAutoFilterValuesChangedEvent() - { - foreach( INotifyCollectionChanged autoFilterValues in m_registeredAutoFilterValuesToFieldNames.Keys ) - CollectionChangedEventManager.RemoveListener( autoFilterValues, this ); - - m_registeredAutoFilterValuesToFieldNames.Clear(); - m_registeredFieldNamesToAutoFilterValues.Clear(); - this.DetailDescriptionAutoFilterValuesChanged = null; - } - - - #endregion - - #region Private Methods - - private void UnregisterAutoFilterValuesChangedEvent( string fieldName ) - { - if( string.IsNullOrEmpty( fieldName ) ) - return; - - INotifyCollectionChanged collectionChanged = null; - - if( !m_registeredFieldNamesToAutoFilterValues.TryGetValue( fieldName, out collectionChanged ) ) - return; - - CollectionChangedEventManager.RemoveListener( collectionChanged, this ); - - m_registeredFieldNamesToAutoFilterValues.Remove( fieldName ); - m_registeredAutoFilterValuesToFieldNames.Remove( collectionChanged ); - } + #region IWeakEventListener Members - private void RaiseDetailDescriptionAutoFilterValuesChangedEvent( AutoFilterValuesChangedEventArgs e ) + bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) { - // Forward this change notification to the root CollectionView - // or CollectionViewSource - if( this.DetailDescriptionAutoFilterValuesChanged != null ) - this.DetailDescriptionAutoFilterValuesChanged( e ); + return this.OnReceiveWeakEvent( managerType, sender, e ); } - private void OnAutoFilterValuesCollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) + protected virtual bool OnReceiveWeakEvent( Type managerType, object sender, EventArgs e ) { - if( this.AutoFilterMode == AutoFilterMode.None ) - return; - - ObservableHashList hashList = sender as ObservableHashList; - - if( hashList == null ) - return; + if( ( managerType == null ) || ( sender == null ) || ( e == null ) ) + return false; - string fieldName = m_registeredAutoFilterValuesToFieldNames[ hashList ]; + if( managerType == typeof( CollectionChangedEventManager ) ) + { + var eventArgs = ( NotifyCollectionChangedEventArgs )e; - if( string.IsNullOrEmpty( fieldName ) ) - return; + if( m_itemProperties == sender ) + { + this.OnItemPropertiesCollectionChanged( sender, eventArgs ); + } + else if( m_detailDescriptions == sender ) + { + } + } + else if( managerType == typeof( InitializeItemPropertyEventManager ) ) + { + var eventArgs = ( InitializeItemPropertyEventArgs )e; - DataGridItemPropertyBase itemProperty = this.ItemProperties[ fieldName ]; + if( m_itemProperties == sender ) + { + var itemProperty = eventArgs.ItemProperty; + var itemPropertyRoute = DataGridItemPropertyRoute.Create( itemProperty ); - if( itemProperty == null ) - return; + ItemsSourceHelper.SetPropertyDescriptionsFromItemProperty( m_defaultPropertyDescriptions, null, null, m_itemType, itemPropertyRoute ); + ItemsSourceHelper.InitializePropertyDescriptions( m_defaultPropertyDescriptions, itemPropertyRoute, m_itemType, this.DefaultPropertyDescriptionsCreated ); + } + } + else + { + return false; + } - this.DetailDescriptionAutoFilterValuesChanged( new AutoFilterValuesChangedEventArgs( this, itemProperty, hashList, e ) ); + return true; } #endregion - #region Private Fields - - private string m_relationName; - private object m_title; - private DataTemplate m_titleTemplate; - private DataGridItemPropertyCollection m_itemProperties; - private DataGridDetailDescriptionCollection m_detailDescriptions; - private DistinctValuesConstraint m_distinctValuesConstraint = DistinctValuesConstraint.All; - private StatFunctionCollection m_statFunctions; - private GroupDescriptionCollection m_groupDescriptions; - private DataGridSortDescriptionCollection m_sortDescriptions; - private ReadOnlyDictionary m_autoFilterValues; - private ObservableCollection m_autoFilteredItems; - private AutoFilterMode m_autoFilterMode = AutoFilterMode.None; - private FilterCriteriaMode m_filterCriteriaMode = FilterCriteriaMode.And; private BitVector32 m_flags = new BitVector32(); - private Dictionary m_registeredFieldNamesToAutoFilterValues; - private Dictionary m_registeredAutoFilterValuesToFieldNames; - - #endregion - - #region DataGridDetailDescriptionFlags Private Classes [Flags] private enum DataGridDetailDescriptionFlags { - IsSealed = 1, - DefaultCalculateDistinctValues = 2, - IsInitialized = 4, - AutoCreateItemProperties = 8, - AutoCreateDetailDescriptions = 16, - AutoCreateForeignKeyDescriptions = 32, - IsAutoCreated = 64, - AutoCreateItemPropertiesCompleted = 128, - AutoCreateDetailDescriptionsCompleted = 256, - } - - #endregion - - #region IWeakEventListener Members - - public bool ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) - { - return this.OnReceiveWeakEvent( managerType, sender, e ); + IsSealed = 1 << 0, + DefaultCalculateDistinctValues = 1 << 1, + IsInitialized = 1 << 2, + AutoCreateItemProperties = 1 << 3, + AutoCreateDetailDescriptions = 1 << 4, + AutoCreateForeignKeyDescriptions = 1 << 5, + IsAutoCreated = 1 << 6, + AutoCreateItemPropertiesCompleted = 1 << 7, + AutoCreateDetailDescriptionsCompleted = 1 << 8, + DefaultItemPropertiesInitialized = 1 << 9, + DefaultPropertyDescriptionsCreated = 1 << 10, } - - protected virtual bool OnReceiveWeakEvent( Type managerType, object sender, EventArgs e ) - { - if( ( managerType == null ) - || ( sender == null ) - || ( e == null ) ) - return false; - - if( managerType == typeof( CollectionChangedEventManager ) ) - { - NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs = - e as NotifyCollectionChangedEventArgs; - - this.OnAutoFilterValuesCollectionChanged( sender, notifyCollectionChangedEventArgs ); - - return true; - } - - return false; - } - - #endregion } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridDetailDescriptionCollection.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridDetailDescriptionCollection.cs index c0574da2..218d3575 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridDetailDescriptionCollection.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridDetailDescriptionCollection.cs @@ -16,7 +16,6 @@ using System; using System.Collections.Generic; -using System.Text; using System.Collections.ObjectModel; namespace Xceed.Wpf.DataGrid @@ -37,9 +36,8 @@ namespace Xceed.Wpf.DataGrid { get { - int index = this.IndexOf( relationName ); - - if( index == -1 ) + var index = this.IndexOf( relationName ); + if( index < 0 ) return null; return this.Items[ index ]; @@ -48,8 +46,8 @@ namespace Xceed.Wpf.DataGrid public int IndexOf( string relationName ) { - IList items = this.Items; - int count = items.Count; + var items = this.Items; + var count = items.Count; for( int i = 0; i < count; i++ ) { @@ -60,20 +58,6 @@ namespace Xceed.Wpf.DataGrid return -1; } - [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly" )] - internal ICollection DefaultDetailDescriptions - { - get - { - return m_defaultDetailDescriptions; - } - set - { - if( m_defaultDetailDescriptions == null ) - m_defaultDetailDescriptions = value; - } - } - protected override void SetItem( int index, DataGridDetailDescription item ) { if( string.IsNullOrEmpty( item.RelationName ) ) @@ -89,22 +73,5 @@ namespace Xceed.Wpf.DataGrid base.InsertItem( index, item ); } - - private DataGridDetailDescription FindDefaultDetailDescription( string name ) - { - if( m_defaultDetailDescriptions != null ) - { - foreach( DataGridDetailDescription detailDescription in m_defaultDetailDescriptions ) - { - if( string.Equals( detailDescription.RelationName, name ) ) - return detailDescription; - } - } - - return null; - } - - private ICollection m_defaultDetailDescriptions; - } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridGroupDescription.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridGroupDescription.cs index c930c2a2..1bd2b380 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridGroupDescription.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridGroupDescription.cs @@ -14,13 +14,10 @@ ***********************************************************************************/ -using System; -using System.Collections.Generic; -using System.Text; +using System.Collections; using System.ComponentModel; using System.Globalization; using System.Windows.Data; -using System.Collections; namespace Xceed.Wpf.DataGrid { @@ -91,7 +88,7 @@ namespace Xceed.Wpf.DataGrid protected object GetPropertyValue( object item ) { if( m_contextProperty != null ) - return m_contextProperty.GetValue( item ); + return ItemsSourceHelper.GetValueFromItemProperty( m_contextProperty, item ); return m_propertyGroupDescription.GroupNameFromItem( item, 0, CultureInfo.InvariantCulture ); } @@ -104,7 +101,7 @@ namespace Xceed.Wpf.DataGrid } else { - string propertyName = m_propertyGroupDescription.PropertyName; + var propertyName = m_propertyGroupDescription.PropertyName; if( string.IsNullOrEmpty( propertyName ) ) { @@ -112,7 +109,7 @@ namespace Xceed.Wpf.DataGrid } else { - m_contextProperty = collectionView.ItemProperties[ propertyName ]; + m_contextProperty = ItemsSourceHelper.GetItemPropertyFromProperty( collectionView.ItemProperties, propertyName ); } } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemProperty.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemProperty.cs index a3797db3..7e4ebe1a 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemProperty.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemProperty.cs @@ -15,29 +15,17 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Text; using System.ComponentModel; -using System.Windows.Data; -using System.Globalization; +using System.Data; using System.Diagnostics; -using System.Collections; -using System.Collections.Specialized; -using System.Collections.ObjectModel; +using System.Globalization; using System.Windows; -using System.Xml; -using System.Data; - -using Xceed.Wpf.DataGrid.Converters; -using Xceed.Wpf.DataGrid.FilterCriteria; namespace Xceed.Wpf.DataGrid { + [DebuggerDisplay( "Name = {Name}" )] public partial class DataGridItemProperty : DataGridItemPropertyBase { - - #region CONSTRUCTORS - public DataGridItemProperty() { } @@ -66,6 +54,7 @@ namespace Xceed.Wpf.DataGrid null, null, null, + null, null ); } @@ -93,6 +82,7 @@ namespace Xceed.Wpf.DataGrid isReadOnly, null, null, + null, null ); } @@ -120,6 +110,7 @@ namespace Xceed.Wpf.DataGrid null, null, null, + null, null ); } @@ -147,6 +138,7 @@ namespace Xceed.Wpf.DataGrid isReadOnly, overrideReadOnlyForInsertion, null, + null, null ); } @@ -169,6 +161,7 @@ namespace Xceed.Wpf.DataGrid null, null, null, + null, null ); } @@ -188,6 +181,7 @@ namespace Xceed.Wpf.DataGrid null, null, null, + null, null ); } @@ -201,6 +195,7 @@ namespace Xceed.Wpf.DataGrid bool isAutoCreated, Nullable isReadOnly, Nullable overrideReadOnlyForInsertion, + Nullable isDisplayable, Nullable isASubRelationship, DataGridForeignKeyDescription foreignKeyDescription ) { @@ -220,17 +215,17 @@ namespace Xceed.Wpf.DataGrid isAutoCreated, isReadOnly, overrideReadOnlyForInsertion, + isDisplayable, isASubRelationship, foreignKeyDescription ); } + [Browsable( false )] + [EditorBrowsable( EditorBrowsableState.Never )] + [Obsolete( "This constructor is obsolete and should no longer be used.", true )] protected DataGridItemProperty( DataGridItemProperty template ) - : base( template ) { - // this.IsAutoCreated = false, after a clone, we consider the ItemProperty not AutoCreated. - m_propertyDescriptor = template.m_propertyDescriptor; - m_valueXPath = template.m_valueXPath; - m_valuePath = template.m_valuePath; + throw new NotSupportedException(); } private void Initialize( @@ -243,6 +238,7 @@ namespace Xceed.Wpf.DataGrid bool isAutoCreated, Nullable isReadOnly, Nullable overrideReadOnlyForInsertion, + Nullable isDisplayable, Nullable isASubRelationship, DataGridForeignKeyDescription foreignKeyDescription ) { @@ -259,7 +255,7 @@ namespace Xceed.Wpf.DataGrid if( m_propertyDescriptor != null ) { - this.Browsable = m_propertyDescriptor.IsBrowsable; + this.IsBrowsable = m_propertyDescriptor.IsBrowsable; if( m_propertyDescriptor.IsReadOnly ) isReadOnly = m_propertyDescriptor.IsReadOnly; @@ -291,11 +287,9 @@ namespace Xceed.Wpf.DataGrid this.ForeignKeyDescription = foreignKeyDescription; - base.Initialize( name, title, dataType, isReadOnly, overrideReadOnlyForInsertion, isASubRelationship ); + base.Initialize( name, title, dataType, isReadOnly, overrideReadOnlyForInsertion, isDisplayable, isASubRelationship ); } - #endregion CONSTRUCTORS - #region ValuePath Property public string ValuePath @@ -306,7 +300,7 @@ namespace Xceed.Wpf.DataGrid } set { - if( this.Initialized ) + if( this.IsSealed ) throw new InvalidOperationException( "An attempt was made to change the ValuePath of a property already added to a containing collection." ); this.SetValuePath( value ); @@ -322,7 +316,7 @@ namespace Xceed.Wpf.DataGrid private string m_valuePath; - #endregion ValuePath Property + #endregion #region ValueXPath Property @@ -334,7 +328,7 @@ namespace Xceed.Wpf.DataGrid } set { - if( this.Initialized ) + if( this.IsSealed ) throw new InvalidOperationException( "An attempt was made to change the ValueXPath of a property already added to a containing collection." ); this.SetValueXPath( value ); @@ -350,7 +344,7 @@ namespace Xceed.Wpf.DataGrid private string m_valueXPath; - #endregion ValueXPath Property + #endregion #region PropertyDescriptor Property @@ -362,7 +356,7 @@ namespace Xceed.Wpf.DataGrid } set { - if( this.Initialized ) + if( this.IsSealed ) throw new InvalidOperationException( "An attempt was made to change the PropertyDescriptor of a property already added to a containing collection." ); this.SetPropertyDescriptor( value ); @@ -374,7 +368,9 @@ namespace Xceed.Wpf.DataGrid m_propertyDescriptor = propertyDescriptor; if( ( m_propertyDescriptor != null ) && ( !this.IsReadOnly ) ) + { this.SetIsReadOnly( propertyDescriptor.IsReadOnly ); + } m_bindingPathValueExtractorForRead = null; m_bindingPathValueExtractorForWrite = null; @@ -382,7 +378,7 @@ namespace Xceed.Wpf.DataGrid private PropertyDescriptor m_propertyDescriptor; - #endregion PropertyDescriptor Property + #endregion #region IsAutoCreated Property @@ -392,23 +388,23 @@ namespace Xceed.Wpf.DataGrid private set; } - #endregion IsAutoCreated Property + #endregion - #region PUBLIC METHODS + #region FieldName Internal Property - public override object Clone() + internal override string FieldName { - Type type = this.GetType(); - - if( type == typeof( DataGridItemProperty ) ) - return new DataGridItemProperty( this ); + get + { + var descriptor = this.PropertyDescriptor; + if( descriptor != null ) + return descriptor.Name; - return base.Clone(); + return base.FieldName; + } } - #endregion PUBLIC METHODS - - #region PROTECTED METHODS + #endregion protected override object GetValueCore( object component ) { @@ -422,20 +418,19 @@ namespace Xceed.Wpf.DataGrid } catch( DataException ) { - // We have to return null if the datarow is deleted from the DataTable. - // When the System.Data.DataRow have RowState == detached, it can be because it has been deleted - // or it being inserted, nothing special found to differentiate that 2 state. So doing a try catch. + // We have to return null if the datarow is deleted from the DataTable. When the System.Data.DataRow has RowState == detached, + // it can be because it has been deleted or it being inserted, nothing special found to differentiate that 2 state. So doing a try catch. value = null; } CultureInfo converterCulture = this.ConverterCulture; if( converterCulture == null ) + { converterCulture = CultureInfo.InvariantCulture; + } - return this.GetBindingConverter( component ).Convert( - value, this.DataType, - this.ConverterParameter, converterCulture ); + return this.GetBindingConverter( component ).Convert( value, this.DataType, this.ConverterParameter, converterCulture ); } if( m_bindingPathValueExtractorForRead == null ) @@ -443,18 +438,19 @@ namespace Xceed.Wpf.DataGrid CultureInfo converterCulture = this.ConverterCulture; if( converterCulture == null ) + { converterCulture = CultureInfo.InvariantCulture; + } PropertyPath propertyPath = null; if( !string.IsNullOrEmpty( this.ValuePath ) ) + { propertyPath = new PropertyPath( this.ValuePath, BindingPathValueExtractor.EmptyObjectArray ); + } - m_bindingPathValueExtractorForRead = new BindingPathValueExtractor( - this.ValueXPath, propertyPath, false, - this.DataType, - this.GetBindingConverter( component ), - this.ConverterParameter, converterCulture ); + m_bindingPathValueExtractorForRead = new BindingPathValueExtractor( this.ValueXPath, propertyPath, false, this.DataType, + this.GetBindingConverter( component ), this.ConverterParameter, converterCulture ); } return m_bindingPathValueExtractorForRead.GetValueFromItem( component ); @@ -467,13 +463,11 @@ namespace Xceed.Wpf.DataGrid CultureInfo converterCulture = this.ConverterCulture; if( converterCulture == null ) + { converterCulture = CultureInfo.InvariantCulture; + } - object convertedValue = this.GetBindingConverter( component ).ConvertBack( - value, - m_propertyDescriptor.PropertyType, - this.ConverterParameter, - converterCulture ); + object convertedValue = this.GetBindingConverter( component ).ConvertBack( value, m_propertyDescriptor.PropertyType, this.ConverterParameter, converterCulture ); m_propertyDescriptor.SetValue( component, convertedValue ); } @@ -484,17 +478,19 @@ namespace Xceed.Wpf.DataGrid CultureInfo converterCulture = this.ConverterCulture; if( converterCulture == null ) + { converterCulture = CultureInfo.InvariantCulture; + } PropertyPath propertyPath = null; if( !string.IsNullOrEmpty( this.ValuePath ) ) + { propertyPath = new PropertyPath( this.ValuePath, BindingPathValueExtractor.EmptyObjectArray ); + } - m_bindingPathValueExtractorForWrite = new BindingPathValueExtractor( - this.ValueXPath, propertyPath, true, - this.DataType, - this.GetBindingConverter( component ), this.ConverterParameter, converterCulture ); + m_bindingPathValueExtractorForWrite = new BindingPathValueExtractor( this.ValueXPath, propertyPath, true, this.DataType, + this.GetBindingConverter( component ), this.ConverterParameter, converterCulture ); } m_bindingPathValueExtractorForWrite.SetValueToItem( component, value ); @@ -503,40 +499,27 @@ namespace Xceed.Wpf.DataGrid base.SetValueCore( component, value ); } - #endregion PROTECTED METHODS - - #region INTERNAL METHODS - internal override PropertyDescriptorFromItemPropertyBase GetPropertyDescriptorForBindingCore() { return new PropertyDescriptorFromItemProperty( this ); } - internal override void SetUnspecifiedPropertiesValues( DataGridItemPropertyCollection itemPropertyCollection ) + internal override void SetUnspecifiedPropertiesValues( + PropertyDescription description, + Type itemType, + bool defaultItemPropertiesCreated ) { - // ContainingCollection.ItemType and ContainingCollection.DefaultItemProperties can be null at first when this is - // the ItemProperties of a DetailGrid. - // the SetUnspecifiedPropertiesValues will be recall when both this.ItemType and this.DefaultItemProperties are affected. + var itemIsXceedDataRow = ( itemType != null ) ? typeof( DataRow ).IsAssignableFrom( itemType ) : false; - if( itemPropertyCollection == null ) - return; - - DataGridItemProperty defaultItemProperty = null; - bool itemIsXceedDataRow = ( itemPropertyCollection.ItemType != null ) ? typeof( DataRow ).IsAssignableFrom( itemPropertyCollection.ItemType ) : false; - - if( ( string.IsNullOrEmpty( this.ValueXPath ) ) - && ( string.IsNullOrEmpty( this.ValuePath ) ) - && ( this.PropertyDescriptor == null ) ) + if( ( this.PropertyDescriptor == null ) && string.IsNullOrEmpty( this.ValuePath ) && string.IsNullOrEmpty( this.ValueXPath ) ) { if( itemIsXceedDataRow ) { - this.PropertyDescriptor = new UnboundDataRowPropertyDescriptor( this.Name, this.DataType ); + this.SetPropertyDescriptor( new UnboundDataRowPropertyDescriptor( this.Name, this.DataType ) ); } else { - defaultItemProperty = itemPropertyCollection.FindDefaultItemProperty( this.Name ) as DataGridItemProperty; - - if( defaultItemProperty == null ) + if( description == null ) { if( this.Name == "." ) { @@ -545,91 +528,71 @@ namespace Xceed.Wpf.DataGrid this.SetIsReadOnly( true ); this.SetOverrideReadOnlyForInsertion( false ); } - else if( itemPropertyCollection.DefaultItemProperties != null ) - { - // I have to add this particular exception case to make sure that when the ItemProperty is "re-normalized" when the first DataGridCollectionView - // is created for it, then the ValuePath is still null or empty (allowing it to be re-normalized) - this.SetValuePath( this.Name ); - } } else { - this.SetPropertyDescriptor( defaultItemProperty.PropertyDescriptor ); - this.SetValuePath( defaultItemProperty.ValuePath ); - this.SetValueXPath( defaultItemProperty.ValueXPath ); + this.SetPropertyDescriptor( description.PropertyDescriptor ); + this.SetValuePath( description.Path ); + this.SetValueXPath( description.XPath ); } } + + if( defaultItemPropertiesCreated && ( this.PropertyDescriptor == null ) && string.IsNullOrEmpty( this.ValuePath ) && string.IsNullOrEmpty( this.ValueXPath ) ) + { + // I have to add this particular exception case to make sure that when the ItemProperty is "re-normalized" when the first DataGridCollectionView + // is created for it, then the ValuePath is still null or empty (allowing it to be re-normalized) + this.SetValuePath( this.Name ); + } } if( this.DataType == null ) { - //only try to affect the DataType if the DefaultItemProperties were set. (will not be the case when XAML parsing DetailDescriptions) - if( itemPropertyCollection.DefaultItemProperties != null ) + //only try to affect the DataType if the DefaultPropertyDescriptions were set. (will not be the case when XAML parsing DetailDescriptions) + if( defaultItemPropertiesCreated ) { - if( defaultItemProperty == null ) - defaultItemProperty = itemPropertyCollection.FindDefaultItemProperty( this.Name ) as DataGridItemProperty; - - if( defaultItemProperty == null ) - { + if( description == null ) throw new InvalidOperationException( "An attempt was made to add an item (" + this.Name + ") without specifying its data type." ); - } - this.SetDataType( defaultItemProperty.DataType ); + this.SetDataType( description.DataType ); } } if( string.IsNullOrEmpty( this.Title ) ) { - if( itemIsXceedDataRow ) + if( !itemIsXceedDataRow && ( description != null ) && !string.IsNullOrEmpty( description.DisplayName ) ) { - this.Title = this.Name; + this.Title = description.DisplayName; } else { - if( defaultItemProperty == null ) - defaultItemProperty = itemPropertyCollection.FindDefaultItemProperty( this.Name ) as DataGridItemProperty; - - if( defaultItemProperty == null ) - { - this.Title = this.Name; - } - else - { - this.Title = defaultItemProperty.Title; - } + this.Title = this.Name; } } if( !this.IsReadOnly ) { - if( defaultItemProperty == null ) - defaultItemProperty = itemPropertyCollection.FindDefaultItemProperty( this.Name ) as DataGridItemProperty; - - if( defaultItemProperty != null ) + if( description != null ) { - this.SetIsReadOnly( defaultItemProperty.IsReadOnly ); + this.SetIsReadOnly( description.IsReadOnly ); } } if( this.OverrideReadOnlyForInsertion == null ) { //only try to affect the DataType if the DefaultItemProperties were set. (will not be the case when XAML parsing DetailDescriptions) - if( itemPropertyCollection.DefaultItemProperties != null ) + if( defaultItemPropertiesCreated ) { - if( defaultItemProperty == null ) - defaultItemProperty = itemPropertyCollection.FindDefaultItemProperty( this.Name ) as DataGridItemProperty; - - this.SetOverrideReadOnlyForInsertion( ( defaultItemProperty != null ) && ( defaultItemProperty.OverrideReadOnlyForInsertion.HasValue ) - ? defaultItemProperty.OverrideReadOnlyForInsertion.Value - : false ); + this.SetOverrideReadOnlyForInsertion( ( description != null ) ? description.OverrideReadOnlyForInsertion : false ); } } if( ( !string.IsNullOrEmpty( this.ValueXPath ) ) && ( string.IsNullOrEmpty( this.ValuePath ) ) ) + { this.SetValuePath( "InnerText" ); + } - bool foreignKeyDescriptionIsNull = ( this.ForeignKeyDescription == null ); - bool foreignKeyDescriptionItemsSourceIsNull = false; + var foreignKeyDescriptionIsNull = ( this.ForeignKeyDescription == null ); + var foreignKeyDescriptionItemsSourceIsNull = false; if( !foreignKeyDescriptionIsNull ) { @@ -639,33 +602,28 @@ namespace Xceed.Wpf.DataGrid // Update the ForeignKeyDescription if not set if( foreignKeyDescriptionIsNull || foreignKeyDescriptionItemsSourceIsNull ) { - if( defaultItemProperty == null ) - defaultItemProperty = itemPropertyCollection.FindDefaultItemProperty( this.Name ) as DataGridItemProperty; - - if( ( defaultItemProperty != null ) && ( defaultItemProperty.ForeignKeyDescription != null ) ) + if( ( description != null ) && ( description.ForeignKeyDescription != null ) ) { if( foreignKeyDescriptionIsNull ) { - this.SetForeignKeyDescription( defaultItemProperty.ForeignKeyDescription ); + this.SetForeignKeyDescription( description.ForeignKeyDescription ); } else { if( foreignKeyDescriptionItemsSourceIsNull ) { - this.ForeignKeyDescription.ItemsSource = defaultItemProperty.ForeignKeyDescription.ItemsSource; + this.ForeignKeyDescription.ItemsSource = description.ForeignKeyDescription.ItemsSource; } } } } } - #endregion INTERNAL METHODS - - #region PRIVATE FIELDS + #region Private Fields private BindingPathValueExtractor m_bindingPathValueExtractorForRead; private BindingPathValueExtractor m_bindingPathValueExtractorForWrite; - #endregion PRIVATE FIELDS + #endregion } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyBase.PropertyDescriptorFromItemPropertyBase.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyBase.PropertyDescriptorFromItemPropertyBase.cs index 75dcb025..dff6b4ae 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyBase.PropertyDescriptorFromItemPropertyBase.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyBase.PropertyDescriptorFromItemPropertyBase.cs @@ -15,10 +15,6 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.ComponentModel; namespace Xceed.Wpf.DataGrid { @@ -27,7 +23,7 @@ namespace Xceed.Wpf.DataGrid internal class PropertyDescriptorFromItemPropertyBase : EmptyDataItemSafePropertyDescriptor { public PropertyDescriptorFromItemPropertyBase( DataGridItemPropertyBase dataGridItemProperty ) - : base( dataGridItemProperty.Name ) + : base( dataGridItemProperty.FieldName ) { m_dataGridItemProperty = new WeakReference( dataGridItemProperty ); m_propertyType = dataGridItemProperty.DataType; diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyBase.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyBase.cs index 1637c45f..a2a3707b 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyBase.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyBase.cs @@ -19,47 +19,43 @@ using System.Collections; using System.ComponentModel; using System.Diagnostics; using System.Globalization; +using System.Threading; using System.Windows.Data; using Xceed.Wpf.DataGrid.Converters; -using Xceed.Wpf.DataGrid.FilterCriteria; +using Xceed.Wpf.DataGrid.Utils; namespace Xceed.Wpf.DataGrid { + [DebuggerDisplay( "Name = {Name}" )] public abstract partial class DataGridItemPropertyBase : INotifyPropertyChanged, ICloneable { + #region Static Fields + + internal static readonly string CalculateDistinctValuesPropertyName = PropertyHelper.GetPropertyName( ( DataGridItemPropertyBase i ) => i.CalculateDistinctValues ); + internal static readonly string ContainingCollectionPropertyName = PropertyHelper.GetPropertyName( ( DataGridItemPropertyBase i ) => i.ContainingCollection ); + internal static readonly string ForeignKeyDescriptionPropertyName = PropertyHelper.GetPropertyName( ( DataGridItemPropertyBase i ) => i.ForeignKeyDescription ); + internal static readonly string GroupSortStatResultPropertyNamePropertyName = PropertyHelper.GetPropertyName( ( DataGridItemPropertyBase i ) => i.GroupSortStatResultPropertyName ); + internal static readonly string IsNameSealedPropertyName = PropertyHelper.GetPropertyName( ( DataGridItemPropertyBase i ) => i.IsNameSealed ); + internal static readonly string IsSealedPropertyName = PropertyHelper.GetPropertyName( ( DataGridItemPropertyBase i ) => i.IsSealed ); + internal static readonly string ItemPropertiesInternalPropertyName = PropertyHelper.GetPropertyName( ( DataGridItemPropertyBase i ) => i.ItemPropertiesInternal ); + internal static readonly string MaxDistinctValuesPropertyName = PropertyHelper.GetPropertyName( ( DataGridItemPropertyBase i ) => i.MaxDistinctValues ); + internal static readonly string SynonymPropertyName = PropertyHelper.GetPropertyName( ( DataGridItemPropertyBase i ) => i.Synonym ); + + #endregion protected DataGridItemPropertyBase() { - this.Browsable = true; + this.SetIsDisplayable( true ); + this.IsBrowsable = true; } + [Browsable( false )] + [EditorBrowsable( EditorBrowsableState.Never )] + [Obsolete( "This constructor is obsolete and should no longer be used.", true )] protected DataGridItemPropertyBase( DataGridItemPropertyBase template ) : this() { - m_name = template.m_name; - m_dataType = template.m_dataType; - m_title = template.m_title; - m_synonym = template.m_synonym; - m_flags[ DataGridItemPropertyBaseFlags.IsReadOnly ] = template.m_flags[ DataGridItemPropertyBaseFlags.IsReadOnly ]; - m_flags[ DataGridItemPropertyBaseFlags.IsOverrideReadOnlyForInsertionSet ] = template.m_flags[ DataGridItemPropertyBaseFlags.IsOverrideReadOnlyForInsertionSet ]; - m_flags[ DataGridItemPropertyBaseFlags.IsOverrideReadOnlyForInsertion ] = template.m_flags[ DataGridItemPropertyBaseFlags.IsOverrideReadOnlyForInsertion ]; - m_flags[ DataGridItemPropertyBaseFlags.IsASubRelationshipSet ] = template.m_flags[ DataGridItemPropertyBaseFlags.IsASubRelationshipSet ]; - m_flags[ DataGridItemPropertyBaseFlags.IsASubRelationship ] = template.m_flags[ DataGridItemPropertyBaseFlags.IsASubRelationship ]; - m_flags[ DataGridItemPropertyBaseFlags.IsBrowsable ] = template.m_flags[ DataGridItemPropertyBaseFlags.IsBrowsable ]; - m_flags[ DataGridItemPropertyBaseFlags.CalculateDistinctValues ] = template.m_flags[ DataGridItemPropertyBaseFlags.CalculateDistinctValues ]; - m_converter = template.m_converter; - m_converterCulture = template.m_converterCulture; - m_converterParameter = template.m_converterParameter; - this.FilterCriterion = template.m_filterCriterion; - m_foreignKeyDescription = template.m_foreignKeyDescription; - m_maxDistinctValues = template.m_maxDistinctValues; - m_sortComparer = template.m_sortComparer; - this.DistinctValuesEqualityComparer = template.DistinctValuesEqualityComparer; - this.DistinctValuesSortComparer = template.DistinctValuesSortComparer; - - // FilterCriterionChanged is not cloned since only used after the clone occurs - this.PropertyChanged += template.PropertyChanged; - this.QueryDistinctValue += template.m_queryDistinctValue; + throw new NotSupportedException(); } protected void Initialize( @@ -68,6 +64,7 @@ namespace Xceed.Wpf.DataGrid Type dataType, Nullable isReadOnly, Nullable overrideReadOnlyForInsertion, + Nullable isDisplayable, Nullable isASubRelationship ) { if( string.IsNullOrEmpty( name ) ) @@ -92,6 +89,11 @@ namespace Xceed.Wpf.DataGrid this.SetOverrideReadOnlyForInsertion( overrideReadOnlyForInsertion ); m_dataType = dataType; + if( isDisplayable.HasValue ) + { + this.SetIsDisplayable( isDisplayable.Value ); + } + if( isASubRelationship != null ) { this.SetIsASubRelationship( isASubRelationship ); @@ -112,7 +114,7 @@ namespace Xceed.Wpf.DataGrid if( string.IsNullOrEmpty( value ) ) throw new ArgumentException( "Name is null (Nothing in Visual Basic) or empty.", "Name" ); - if( this.Initialized ) + if( this.IsNameSealed || this.IsSealed ) throw new InvalidOperationException( "An attempt was made to change the name of a property already added to a containing collection." ); m_name = value; @@ -121,7 +123,7 @@ namespace Xceed.Wpf.DataGrid private string m_name; - #endregion Name Property + #endregion #region DataType Property @@ -134,7 +136,7 @@ namespace Xceed.Wpf.DataGrid } set { - if( this.Initialized ) + if( this.IsSealed ) throw new InvalidOperationException( "An attempt was made to change the DataType of a property already added to a containing collection." ); this.SetDataType( value ); @@ -151,7 +153,7 @@ namespace Xceed.Wpf.DataGrid private Type m_dataType; - #endregion DataType Property + #endregion #region IsReadOnly Property @@ -163,7 +165,7 @@ namespace Xceed.Wpf.DataGrid } set { - if( this.Initialized ) + if( this.IsSealed ) throw new InvalidOperationException( "An attempt was made to change the IsReadOnly property of a DataGridItemProperty already added to a containing collection." ); this.SetIsReadOnly( value ); @@ -175,7 +177,7 @@ namespace Xceed.Wpf.DataGrid m_flags[ DataGridItemPropertyBaseFlags.IsReadOnly ] = isReadOnly; } - #endregion IsReadOnly Property + #endregion #region OverrideReadOnlyForInsertion Property @@ -190,7 +192,7 @@ namespace Xceed.Wpf.DataGrid } set { - if( this.Initialized ) + if( this.IsSealed ) throw new InvalidOperationException( "An attempt was made to change the OverrideReadOnlyForInsertion property of a DataGridItemProperty already added to a containing collection." ); this.SetOverrideReadOnlyForInsertion( value ); @@ -211,47 +213,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion OverrideReadOnlyForInsertion Property - - #region IsASubRelationship Property - - internal bool IsASubRelationship - { - get - { - if( m_flags[ DataGridItemPropertyBaseFlags.IsASubRelationshipSet ] ) - return m_flags[ DataGridItemPropertyBaseFlags.IsASubRelationship ]; - - if( m_dataType == null ) - return false; - - bool isASubRelationship = ItemsSourceHelper.IsASubRelationship( m_dataType ); - - if( this.Initialized ) - { - m_flags[ DataGridItemPropertyBaseFlags.IsASubRelationship ] = isASubRelationship; - m_flags[ DataGridItemPropertyBaseFlags.IsASubRelationshipSet ] = true; - } - - return isASubRelationship; - } - } - - private void SetIsASubRelationship( Nullable isASubRelationship ) - { - if( isASubRelationship.HasValue ) - { - m_flags[ DataGridItemPropertyBaseFlags.IsASubRelationship ] = isASubRelationship.Value; - m_flags[ DataGridItemPropertyBaseFlags.IsASubRelationshipSet ] = true; - } - else - { - m_flags[ DataGridItemPropertyBaseFlags.IsASubRelationshipSet - | DataGridItemPropertyBaseFlags.IsASubRelationship ] = false; - } - } - - #endregion IsASubRelationship Property + #endregion #region Title Property @@ -273,7 +235,7 @@ namespace Xceed.Wpf.DataGrid private string m_title; - #endregion Title Property + #endregion #region Synonym Property @@ -286,7 +248,7 @@ namespace Xceed.Wpf.DataGrid } set { - if( this.Initialized ) + if( this.IsSealed ) throw new InvalidOperationException( "An attempt was made to change the Synonym of a property already added to a containing collection." ); this.SetSynonym( value ); @@ -295,12 +257,21 @@ namespace Xceed.Wpf.DataGrid internal void SetSynonym( string value ) { + if( value == m_synonym ) + return; + + var wasSealed = this.IsSealed; + this.IsSealed = false; + m_synonym = value; + + this.IsSealed = wasSealed; + this.OnPropertyChanged( DataGridItemPropertyBase.SynonymPropertyName ); } private string m_synonym; - #endregion Synonym Property + #endregion #region SortComparer Property @@ -318,7 +289,7 @@ namespace Xceed.Wpf.DataGrid private IComparer m_sortComparer; - #endregion SortComparer Property + #endregion #region Converter Property @@ -330,7 +301,7 @@ namespace Xceed.Wpf.DataGrid } set { - if( this.Initialized ) + if( this.IsSealed ) throw new InvalidOperationException( "An attempt was made to change the Converter property of a DataGridItemProperty already added to a containing collection." ); m_converter = value; @@ -339,7 +310,7 @@ namespace Xceed.Wpf.DataGrid internal IValueConverter GetBindingConverter( object sourceItem ) { - if( !this.Initialized ) + if( !this.IsSealed ) throw new InvalidOperationException( "An attempt was made to apply a binding to a DataGridItemProperty that has not be added to the ItemProperties collection." ); if( m_bindingConverter == null ) @@ -350,9 +321,7 @@ namespace Xceed.Wpf.DataGrid } else { - m_bindingConverter = new SourceDataConverter( - ItemsSourceHelper.IsItemSupportingDBNull( sourceItem ), - CultureInfo.InvariantCulture ); + m_bindingConverter = new SourceDataConverter( ItemsSourceHelper.IsItemSupportingDBNull( sourceItem ), CultureInfo.InvariantCulture ); } } @@ -362,7 +331,7 @@ namespace Xceed.Wpf.DataGrid private IValueConverter m_converter; private IValueConverter m_bindingConverter; - #endregion Converter Property + #endregion #region ConverterCulture Property @@ -374,7 +343,7 @@ namespace Xceed.Wpf.DataGrid } set { - if( this.Initialized ) + if( this.IsSealed ) throw new InvalidOperationException( "An attempt was made to change the ConverterCulture property of a DataGridItemProperty already added to a containing collection." ); m_converterCulture = value; @@ -383,7 +352,7 @@ namespace Xceed.Wpf.DataGrid private CultureInfo m_converterCulture; - #endregion ConverterCulture Property + #endregion #region ConverterParameter Property @@ -395,7 +364,7 @@ namespace Xceed.Wpf.DataGrid } set { - if( this.Initialized ) + if( this.IsSealed ) throw new InvalidOperationException( "An attempt was made to change the ConverterParameter property of a DataGridItemProperty already added to a containing collection." ); m_converterParameter = value; @@ -404,56 +373,7 @@ namespace Xceed.Wpf.DataGrid private object m_converterParameter; - #endregion ConverterParameter Property - - #region FilterCriterion Property - - public FilterCriterion FilterCriterion - { - get - { - return m_filterCriterion; - } - - set - { - if( value != m_filterCriterion ) - { - if( m_filterCriterion != null ) - m_filterCriterion.PropertyChanged -= new PropertyChangedEventHandler( FilterCriterion_PropertyChanged ); - - m_filterCriterion = value; - - this.RaiseFilterCriterionChanged(); - - if( m_filterCriterion != null ) - m_filterCriterion.PropertyChanged += new PropertyChangedEventHandler( FilterCriterion_PropertyChanged ); - - this.OnPropertyChanged( "FilterCriterion" ); - } - } - } - - private void FilterCriterion_PropertyChanged( object sender, PropertyChangedEventArgs e ) - { - this.RaiseFilterCriterionChanged(); - } - - private void RaiseFilterCriterionChanged() - { - if( this.FilterCriterionChanged != null ) - this.FilterCriterionChanged( this, EventArgs.Empty ); - } - - - // Triggered if the instance of FilterCriterion changes, if a property of the - // FilterCriterion changes or if a property of one of the child FilterCriterion - // changes. - internal event EventHandler FilterCriterionChanged; - - private FilterCriterion m_filterCriterion; // = null; - - #endregion FilterCriterion Property + #endregion #region CalculateDistinctValues Property @@ -472,7 +392,7 @@ namespace Xceed.Wpf.DataGrid if( value != m_flags[ DataGridItemPropertyBaseFlags.CalculateDistinctValues ] ) { m_flags[ DataGridItemPropertyBaseFlags.CalculateDistinctValues ] = value; - this.OnPropertyChanged( "CalculateDistinctValues" ); + this.OnPropertyChanged( DataGridItemPropertyBase.CalculateDistinctValuesPropertyName ); } this.IsCalculateDistinctValuesInitialized = true; @@ -491,7 +411,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion CalculateDistinctValues Property + #endregion #region MaxDistinctValues Property @@ -506,14 +426,14 @@ namespace Xceed.Wpf.DataGrid if( m_maxDistinctValues != value ) { m_maxDistinctValues = value; - this.OnPropertyChanged( "MaxDistinctValues" ); + this.OnPropertyChanged( DataGridItemPropertyBase.MaxDistinctValuesPropertyName ); } } } private int m_maxDistinctValues = -1; // -1 ==> no maximum - #endregion MaxDistinctValues Property + #endregion #region DistinctValuesSortComparer Property @@ -535,115 +455,281 @@ namespace Xceed.Wpf.DataGrid #endregion - #region Initialized Property + #region ForeignKeyDescription Property - internal bool Initialized + public DataGridForeignKeyDescription ForeignKeyDescription { get { - return m_flags[ DataGridItemPropertyBaseFlags.IsInitialized ]; + return m_foreignKeyDescription; } set { - Debug.Assert( value ); + this.SetForeignKeyDescription( value ); + } + } - m_flags[ DataGridItemPropertyBaseFlags.IsInitialized ] = value; + internal void SetForeignKeyDescription( DataGridForeignKeyDescription description ) + { + if( m_foreignKeyDescription != description ) + { + m_foreignKeyDescription = description; + this.OnPropertyChanged( DataGridItemPropertyBase.ForeignKeyDescriptionPropertyName ); } } - #endregion Initialized Property + private DataGridForeignKeyDescription m_foreignKeyDescription; // = null; - #region Browsable Property + #endregion - // That property only indicate for the DefaultProperties generated if - // the property should take place in the real property list by default. - internal bool Browsable + #region GroupSortStatResultPropertyName Property + + public string GroupSortStatResultPropertyName { get { - return m_flags[ DataGridItemPropertyBaseFlags.IsBrowsable ]; + return m_groupSortStatResultPropertyName; } set { - m_flags[ DataGridItemPropertyBaseFlags.IsBrowsable ] = value; + if( value == m_groupSortStatResultPropertyName ) + return; + + m_groupSortStatResultPropertyName = value; + + this.OnPropertyChanged( DataGridItemPropertyBase.GroupSortStatResultPropertyNamePropertyName ); } } - #endregion Browsable Property + private string m_groupSortStatResultPropertyName; - #region ForeignKeyDescription Property + #endregion - public DataGridForeignKeyDescription ForeignKeyDescription + #region GroupSortStatResultComparer Property + + public IComparer GroupSortStatResultComparer + { + get; + set; + } + + #endregion + + #region IsDisplayable Property + + public bool IsDisplayable { get { - return m_foreignKeyDescription; + return m_flags[ DataGridItemPropertyBaseFlags.IsDisplayable ]; } set { - this.SetForeignKeyDescription( value ); + if( this.IsSealed ) + throw new InvalidOperationException( "An attempt was made to change the IsDisplayable property of a DataGridItemProperty already added to a containing collection." ); + + this.SetIsDisplayable( value ); } } - internal void SetForeignKeyDescription( DataGridForeignKeyDescription description ) + internal void SetIsDisplayable( bool value ) { - if( m_foreignKeyDescription != description ) + m_flags[ DataGridItemPropertyBaseFlags.IsDisplayable ] = value; + } + + #endregion + + #region ItemProperties Property + + public DataGridItemPropertyCollection ItemProperties + { + get { - m_foreignKeyDescription = description; - this.OnPropertyChanged( "ForeignKeyDescription" ); + if( m_itemProperties == null ) + { + Interlocked.CompareExchange( ref m_itemProperties, new DataGridItemPropertyCollection( this ), null ); + Debug.Assert( m_itemProperties != null ); + + this.OnPropertyChanged( DataGridItemPropertyBase.ItemPropertiesInternalPropertyName ); + } + + return m_itemProperties; } } - private DataGridForeignKeyDescription m_foreignKeyDescription; // = null; + internal DataGridItemPropertyCollection ItemPropertiesInternal + { + get + { + return m_itemProperties; + } + } - #endregion ForeignKeyDescription Property + private DataGridItemPropertyCollection m_itemProperties; - #region GroupSortStatResultPropertyName Property + #endregion - public string GroupSortStatResultPropertyName + #region FieldName Internal Property + + internal virtual string FieldName { get { - return m_groupSortStatResultPropertyName; + return this.Name; + } + } + + #endregion + + #region IsNameSealed Internal Property + + internal bool IsNameSealed + { + get + { + return m_flags[ DataGridItemPropertyBaseFlags.IsNameSealed ]; } set { - if( m_groupSortStatResultPropertyName != value ) - { - m_groupSortStatResultPropertyName = value; + if( value == this.IsNameSealed ) + return; + + m_flags[ DataGridItemPropertyBaseFlags.IsNameSealed ] = value; + + this.OnPropertyChanged( DataGridItemPropertyBase.IsNameSealedPropertyName ); + } + } + + #endregion + + #region IsSealed Internal Property + + internal bool IsSealed + { + get + { + return m_flags[ DataGridItemPropertyBaseFlags.IsSealed ]; + } + set + { + if( value == this.IsSealed ) + return; + + m_flags[ DataGridItemPropertyBaseFlags.IsSealed ] = value; + + this.OnPropertyChanged( DataGridItemPropertyBase.IsSealedPropertyName ); + } + } + + #endregion + + #region IsBrowsable Internal Property + + // That property only indicates for the DefaultProperties generated if the property should take place in the real property list by default. + internal bool IsBrowsable + { + get + { + return m_flags[ DataGridItemPropertyBaseFlags.IsBrowsable ]; + } + set + { + m_flags[ DataGridItemPropertyBaseFlags.IsBrowsable ] = value; + } + } + + #endregion + + #region IsASubRelationship Internal Property + + internal bool IsASubRelationship + { + get + { + if( m_flags[ DataGridItemPropertyBaseFlags.IsASubRelationshipSet ] ) + return m_flags[ DataGridItemPropertyBaseFlags.IsASubRelationship ]; - this.OnPropertyChanged( "GroupSortStatResultPropertyName" ); + if( m_dataType == null ) + return false; + + bool isASubRelationship = ItemsSourceHelper.IsASubRelationship( m_dataType ); + + if( this.IsSealed ) + { + m_flags[ DataGridItemPropertyBaseFlags.IsASubRelationship ] = isASubRelationship; + m_flags[ DataGridItemPropertyBaseFlags.IsASubRelationshipSet ] = true; } + + return isASubRelationship; } } - private string m_groupSortStatResultPropertyName; + private void SetIsASubRelationship( Nullable isASubRelationship ) + { + if( isASubRelationship.HasValue ) + { + m_flags[ DataGridItemPropertyBaseFlags.IsASubRelationship ] = isASubRelationship.Value; + m_flags[ DataGridItemPropertyBaseFlags.IsASubRelationshipSet ] = true; + } + else + { + m_flags[ DataGridItemPropertyBaseFlags.IsASubRelationshipSet + | DataGridItemPropertyBaseFlags.IsASubRelationship ] = false; + } + } - #endregion GroupSortStatResultPropertyName Property + #endregion - #region GroupSortStatResultComparer Property + #region IsSortingOnForeignKeyDescription Internal Property - public IComparer GroupSortStatResultComparer + internal bool IsSortingOnForeignKeyDescription { get; set; } - #endregion GroupSortStatResultComparer Property + #endregion - #region ValueChanged Event + #region ContainingCollection Internal Property - private void OnValueChanged( ValueChangedEventArgs e ) + internal DataGridItemPropertyCollection ContainingCollection { - if( this.ValueChanged != null ) + get { - this.ValueChanged( this, e ); + return m_containingCollection; + } + private set + { + if( value == m_containingCollection ) + return; + + if( ( value != null ) && ( m_containingCollection != null ) ) + throw new InvalidOperationException( "The property is already assigned to a DataGridItemPropertyCollection." ); + + m_containingCollection = value; + + this.OnPropertyChanged( DataGridItemPropertyBase.ContainingCollectionPropertyName ); } } + private DataGridItemPropertyCollection m_containingCollection; //null + + #endregion + + #region ValueChanged Internal Event + internal event EventHandler ValueChanged; - #endregion ComponentValueChanged Event + private void OnValueChanged( ValueChangedEventArgs e ) + { + var handler = this.ValueChanged; + if( handler == null ) + return; + + handler.Invoke( this, e ); + } + + #endregion #region DistinctValueSelector Event @@ -677,68 +763,47 @@ namespace Xceed.Wpf.DataGrid public object GetValue( object component ) { - // Since EmptyDataItemSafePropertyDescriptor ensure - // to return null to avoid Binding exceptions when a - // CollectionView other than the DataGridCollectionView - // is used, we must return null to avoid calling - // GetValueCore using null as component - if( ( component == null ) - || ( component is EmptyDataItem ) ) - return null; - - UnboundDataItem unboundDataItem = component as UnboundDataItem; - + var unboundDataItem = component as UnboundDataItem; if( unboundDataItem != null ) + { component = unboundDataItem.DataItem; + } + + // Since EmptyDataItemSafePropertyDescriptor ensures to return null to avoid Binding exceptions when a CollectionView other + // than the DataGridCollectionView is used, we must return null to avoid calling GetValueCore using null as component. + if( ( component == null ) || ( component is EmptyDataItem ) ) + return null; return this.GetValueCore( component ); } public void SetValue( object component, object value ) { - if( component is EmptyDataItem ) - throw new InvalidOperationException( "An attempt was made to set a value on an empty data item." ); - - UnboundDataItem unboundDataItem = component as UnboundDataItem; - + var unboundDataItem = component as UnboundDataItem; if( unboundDataItem != null ) { component = unboundDataItem.DataItem; } - bool isReadOnly = ( this.OverrideReadOnlyForInsertion.HasValue && this.OverrideReadOnlyForInsertion.Value ) ? false : this.IsReadOnly; + if( component == null ) + throw new InvalidOperationException( "An attempt was made to set a value on a null data item." ); + + if( component is EmptyDataItem ) + throw new InvalidOperationException( "An attempt was made to set a value on an empty data item." ); - if( isReadOnly ) + if( this.IsReadOnly && !this.OverrideReadOnlyForInsertion.GetValueOrDefault( false ) ) throw new InvalidOperationException( "An attempt was made to set a read-only property." ); this.SetValueCore( component, value ); } + [Browsable( false )] + [EditorBrowsable( EditorBrowsableState.Never )] + [Obsolete( "The ICloneable interface is no longer supported.", true )] public virtual object Clone() { - try - { - return Activator.CreateInstance( this.GetType(), this ); - } - catch( Exception exception ) - { - throw new NotImplementedException( "An attempt was made to Clone an instance of type " + this.GetType().ToString() + " that does not override the Clone() method.", exception ); - } - } - -#if DEBUG - public override string ToString() - { - if( this.Name != null ) - { - return this.GetType() + ": " + this.Name; - } - else - { - return this.GetType().ToString(); - } + throw new NotSupportedException(); } -#endif protected abstract object GetValueCore( object component ); @@ -750,7 +815,9 @@ namespace Xceed.Wpf.DataGrid internal PropertyDescriptorFromItemPropertyBase GetPropertyDescriptorForBinding() { if( m_propertyDescriptorFromItemProperty == null ) + { m_propertyDescriptorFromItemProperty = this.GetPropertyDescriptorForBindingCore(); + } return m_propertyDescriptorFromItemProperty; } @@ -760,18 +827,34 @@ namespace Xceed.Wpf.DataGrid return new PropertyDescriptorFromItemPropertyBase( this ); } - internal virtual void SetUnspecifiedPropertiesValues( DataGridItemPropertyCollection itemPropertyCollection ) + internal virtual void SetUnspecifiedPropertiesValues( PropertyDescription description, Type itemType, bool defaultItemPropertiesCreated ) { } + internal void AttachToContainingCollection( DataGridItemPropertyCollection collection ) + { + if( collection == null ) + throw new ArgumentNullException( "collection" ); + + this.ContainingCollection = collection; + } + + internal void DetachFromContainingCollection() + { + this.ContainingCollection = null; + } + #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged( string propertyName ) { - if( this.PropertyChanged != null ) - this.PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) ); + var handler = this.PropertyChanged; + if( handler == null ) + return; + + handler.Invoke( this, new PropertyChangedEventArgs( propertyName ) ); } #endregion @@ -779,6 +862,8 @@ namespace Xceed.Wpf.DataGrid private PropertyDescriptorFromItemPropertyBase m_propertyDescriptorFromItemProperty; private BitFlags m_flags; + #region ValueChangedEventArgs Internal Class + internal class ValueChangedEventArgs : EventArgs { public ValueChangedEventArgs( object component ) @@ -793,6 +878,10 @@ namespace Xceed.Wpf.DataGrid } } + #endregion + + #region BitFlags Private Struct + private struct BitFlags { internal bool this[ DataGridItemPropertyBaseFlags flag ] @@ -841,6 +930,10 @@ namespace Xceed.Wpf.DataGrid private DataGridItemPropertyBaseFlags m_data; } + #endregion + + #region DataGridItemPropertyBaseFlags Private Enum + [Flags] private enum DataGridItemPropertyBaseFlags : ushort { @@ -851,8 +944,12 @@ namespace Xceed.Wpf.DataGrid IsASubRelationship = 0x0010, CalculateDistinctValues = 0x0020, IsCalculateDistinctValuesInitialized = 0x0040, - IsInitialized = 0x0080, - IsBrowsable = 0x0100, + IsNameSealed = 0x0080, + IsSealed = 0x0100, + IsBrowsable = 0x0200, + IsDisplayable = 0x0400, } + + #endregion } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyCollection.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyCollection.cs index cf3c2069..16793294 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyCollection.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyCollection.cs @@ -15,430 +15,964 @@ ***********************************************************************************/ using System; +using System.Collections; using System.Collections.Generic; -using System.Text; -using System.Collections.ObjectModel; +using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; -using System.Collections; +using System.Linq; +using System.Threading; +using Xceed.Utils.Wpf; +using Xceed.Wpf.DataGrid.Utils; namespace Xceed.Wpf.DataGrid { - public class DataGridItemPropertyCollection : ObservableCollection + [DebuggerDisplay( "Count = {Count}" )] + public sealed class DataGridItemPropertyCollection : + IList, + IList, + ICollection, + ICollection, + IEnumerable, + IEnumerable, + INotifyCollectionChanged, + INotifyPropertyChanged { + #region Static Fields + + private static readonly string CountPropertyName = PropertyHelper.GetPropertyName( ( DataGridItemPropertyCollection c ) => c.Count ); + private static readonly string ItemsPropertyName = "Item[]"; + + #endregion + internal DataGridItemPropertyCollection() - : base() + : this( null ) { } + internal DataGridItemPropertyCollection( DataGridItemPropertyBase owner ) + { + m_owner = owner; + } + + #region [] Property + public DataGridItemPropertyBase this[ string name ] { get { - int index = this.IndexOf( name ); + if( !string.IsNullOrEmpty( name ) ) + { + DataGridItemPropertyBase item; + if( m_nameToItem.TryGetValue( name, out item ) ) + return item; + } + + return null; + } + set + { + if( value == null ) + throw new ArgumentNullException( "value" ); + + if( string.IsNullOrEmpty( value.Name ) ) + throw new ArgumentException( "An attempt was made to add an item that does not have a name.", "value" ); - if( index == -1 ) - return null; + if( value.Name != name ) + throw new ArgumentException( "The item's name is not the same as the parameter.", "name" ); - return this.Items[ index ]; + var oldItem = this[ name ]; + if( oldItem == null ) + { + this.InsertItemAndNotify( m_collection.Count, value ); + } + else + { + if( value == oldItem ) + return; + + var index = this.IndexOf( oldItem ); + Debug.Assert( index >= 0 ); + + this.ReplaceItemAndNotify( index, oldItem, value ); + } } } - public int IndexOf( string name ) + #endregion + + #region DataGridItemPropertyBase Internal Owner + + internal DataGridItemPropertyBase Owner { - IList items = this.Items; - int count = items.Count; + get + { + return m_owner; + } + } + + private readonly DataGridItemPropertyBase m_owner; - for( int i = 0; i < count; i++ ) + #endregion + + #region SyncRoot Private Property + + private object SyncRoot + { + get { - if( string.Equals( items[ i ].Name, name ) ) - return i; + return ( ( ICollection )this ).SyncRoot; } + } - return -1; + #endregion + + #region ItemPropertyGroupSortStatNameChanged Internal Event + + internal event EventHandler ItemPropertyGroupSortStatNameChanged; + + private void OnItemPropertyGroupSortStatNameChanged() + { + var handler = this.ItemPropertyGroupSortStatNameChanged; + if( handler == null ) + return; + + handler.Invoke( this, EventArgs.Empty ); } - public event EventHandler FilterCriterionChanged; + #endregion + + #region InitializeItemProperty Internal Event + + internal event EventHandler InitializeItemProperty; - protected override void ClearItems() + private void OnInitializeItemProperty( DataGridItemPropertyBase itemProperty ) { - DataGridItemPropertyBase[] oldItems = new DataGridItemPropertyBase[ this.Count ]; - this.CopyTo( oldItems, 0 ); + var handler = this.InitializeItemProperty; + if( handler == null ) + return; - m_unboundItemPropertyCount = 0; - base.ClearItems(); + handler.Invoke( this, new InitializeItemPropertyEventArgs( itemProperty ) ); + } - for( int i = 0; i < oldItems.Length; i++ ) - { - DataGridItemPropertyBase oldItem = oldItems[ i ]; - oldItem.FilterCriterionChanged -= new EventHandler( DataGridItemProperty_FilterCriterionChanged ); - oldItem.ValueChanged -= new EventHandler( DataGridItemProperty_ValueChanged ); - } + private void RelayInitializeItemProperty( InitializeItemPropertyEventArgs e ) + { + var handler = this.InitializeItemProperty; + if( handler == null ) + return; + + Debug.Assert( e != null ); + + handler.Invoke( this, e ); } - protected override void RemoveItem( int index ) + #endregion + + internal IDisposable DeferCollectionChanged() { - DataGridItemPropertyBase oldItem = null; + return new DeferredDisposable( new DeferState( this ) ); + } - if( index < this.Count ) - { - oldItem = this[ index ]; - } + internal bool Contains( string name ) + { + if( string.IsNullOrEmpty( name ) ) + return false; + + return m_nameToItem.ContainsKey( name ); + } + + internal DataGridItemPropertyBase GetForSynonym( string name ) + { + if( string.IsNullOrEmpty( name ) ) + return null; + + DataGridItemPropertyBase[] synonyms; + if( !m_synonymToItem.TryGetValue( name, out synonyms ) ) + return null; + + Debug.Assert( synonyms.Length > 0 ); + if( synonyms.Length <= 0 ) + return null; + + return synonyms[ 0 ]; + } - base.RemoveItem( index ); + internal void RefreshUnboundItemProperty( object component ) + { + if( m_unboundItems.Count <= 0 || ( component == null ) ) + return; - if( oldItem != null ) + var unboundDataItem = UnboundDataItem.GetUnboundDataItem( component ); + if( unboundDataItem == null ) + return; + + var dataItem = unboundDataItem.DataItem; + if( ( dataItem == null ) || ( dataItem is EmptyDataItem ) ) + return; + + State state; + if( m_dataItems.TryGetValue( dataItem, out state ) && ( state.Refreshing || state.Suspended ) ) + return; + + m_dataItems.Add( dataItem, new State( true, false ) ); + + try { - if( oldItem is DataGridUnboundItemProperty ) + foreach( var item in m_unboundItems ) { - m_unboundItemPropertyCount--; + item.Refresh( unboundDataItem ); } + } + finally + { + state = m_dataItems[ dataItem ]; - oldItem.FilterCriterionChanged -= new EventHandler( DataGridItemProperty_FilterCriterionChanged ); - oldItem.ValueChanged -= new EventHandler( DataGridItemProperty_ValueChanged ); - oldItem.PropertyChanged -= new PropertyChangedEventHandler( OnDataGridItemProperty_PropertyChanged ); + if( state.Suspended ) + { + m_dataItems[ dataItem ] = new State( false, true ); + } + else + { + m_dataItems.Remove( dataItem ); + } } } - protected override void SetItem( int index, DataGridItemPropertyBase item ) + internal void SuspendUnboundItemPropertyChanged( object component ) { - if( string.IsNullOrEmpty( item.Name ) ) - throw new InvalidOperationException( "An attempt was made to add an item that does not have a name." ); + if( component == null ) + return; - DataGridItemPropertyBase oldItem = null; + var unboundDataItem = UnboundDataItem.GetUnboundDataItem( component ); + if( unboundDataItem == null ) + return; + + var dataItem = unboundDataItem.DataItem; + if( ( dataItem == null ) || ( dataItem is EmptyDataItem ) ) + return; - if( index < this.Count ) + State state; + bool refreshing = false; + + if( m_dataItems.TryGetValue( dataItem, out state ) ) { - oldItem = this[ index ]; + if( state.Suspended ) + return; + + refreshing = state.Refreshing; } - if( item == oldItem ) + m_dataItems[ dataItem ] = new State( refreshing, true ); + } + + internal void ResumeUnboundItemPropertyChanged( object component ) + { + if( component == null ) + return; + + var unboundDataItem = UnboundDataItem.GetUnboundDataItem( component ); + if( unboundDataItem == null ) + return; + + var dataItem = unboundDataItem.DataItem; + if( ( dataItem == null ) || ( dataItem is EmptyDataItem ) ) + return; + + State state; + if( !m_dataItems.TryGetValue( dataItem, out state ) || !state.Suspended ) { - base.SetItem( index, item ); + Debug.Fail( "The item is not suspended." ); return; } - item.ValueChanged += new EventHandler( DataGridItemProperty_ValueChanged ); - item.PropertyChanged += new PropertyChangedEventHandler( OnDataGridItemProperty_PropertyChanged ); - item.SetUnspecifiedPropertiesValues( this ); - - try + if( state.Refreshing ) { - base.SetItem( index, item ); + m_dataItems[ dataItem ] = new State( true, false ); } - catch + else { - item.ValueChanged -= new EventHandler( DataGridItemProperty_ValueChanged ); - item.PropertyChanged -= new PropertyChangedEventHandler( OnDataGridItemProperty_PropertyChanged ); - throw; + m_dataItems.Remove( dataItem ); + + this.RefreshUnboundItemProperty( dataItem ); } + } + + private static NotifyCollectionChangedEventArgs Combine( NotifyCollectionChangedEventArgs x, NotifyCollectionChangedEventArgs y ) + { + if( x == null ) + return y; + + if( y == null ) + return x; + + var addedItems = DataGridItemPropertyCollection.GetAddedItems( x ).ToList(); + var removedItems = DataGridItemPropertyCollection.GetRemovedItems( x ).ToList(); - if( item is DataGridUnboundItemProperty ) + foreach( var item in DataGridItemPropertyCollection.GetAddedItems( y ) ) { - m_unboundItemPropertyCount++; + if( !removedItems.Remove( item ) ) + { + Debug.Assert( !addedItems.Contains( item ) ); + addedItems.Add( item ); + } } - if( oldItem != null ) + foreach( var item in DataGridItemPropertyCollection.GetRemovedItems( y ) ) { - if( oldItem is DataGridUnboundItemProperty ) + if( !addedItems.Remove( item ) ) { - m_unboundItemPropertyCount--; + Debug.Assert( !removedItems.Contains( item ) ); + removedItems.Add( item ); } + } - oldItem.FilterCriterionChanged -= new EventHandler( DataGridItemProperty_FilterCriterionChanged ); - oldItem.ValueChanged -= new EventHandler( DataGridItemProperty_ValueChanged ); - oldItem.PropertyChanged -= new PropertyChangedEventHandler( OnDataGridItemProperty_PropertyChanged ); + var addedItemsCount = addedItems.Count; + var removedItemsCount = removedItems.Count; + + if( ( addedItemsCount > 0 ) && ( removedItemsCount > 0 ) ) + { + if( ( x.Action != NotifyCollectionChangedAction.Replace ) || ( y.Action != NotifyCollectionChangedAction.Replace ) || ( addedItemsCount != removedItemsCount ) ) + throw new NotSupportedException(); + + return new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Replace, addedItems, removedItems ); } - item.FilterCriterionChanged += new EventHandler( DataGridItemProperty_FilterCriterionChanged ); - item.Initialized = true; + if( addedItemsCount > 0 ) + return new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Add, addedItems ); + + if( removedItemsCount > 0 ) + return new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Remove, removedItems ); + + return null; + } + + private static IEnumerable GetAddedItems( NotifyCollectionChangedEventArgs source ) + { + if( ( source != null ) && ( source.NewItems != null ) ) + return source.NewItems.Cast(); + + return Enumerable.Empty(); + } + + private static IEnumerable GetRemovedItems( NotifyCollectionChangedEventArgs source ) + { + if( ( source != null ) && ( source.OldItems != null ) ) + return source.OldItems.Cast(); + + return Enumerable.Empty(); + } + + private void InsertItemAndNotify( int index, DataGridItemPropertyBase item ) + { + this.InsertItem( index, item ); + + this.OnPropertyChanged( DataGridItemPropertyCollection.CountPropertyName ); + this.OnPropertyChanged( DataGridItemPropertyCollection.ItemsPropertyName ); + this.OnCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Add, item, index ) ); + } + + private void ReplaceItemAndNotify( int index, DataGridItemPropertyBase oldItem, DataGridItemPropertyBase newItem ) + { + this.RemoveItem( index, oldItem ); + this.InsertItem( index, newItem ); + + this.OnPropertyChanged( DataGridItemPropertyCollection.ItemsPropertyName ); + this.OnCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Replace, newItem, oldItem, index ) ); + } + + private void RemoveItemAndNotify( int index, DataGridItemPropertyBase item ) + { + this.RemoveItem( index, item ); + + this.OnPropertyChanged( DataGridItemPropertyCollection.CountPropertyName ); + this.OnPropertyChanged( DataGridItemPropertyCollection.ItemsPropertyName ); + this.OnCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Remove, item, index ) ); } - protected override void InsertItem( int index, DataGridItemPropertyBase item ) + private void InsertItem( int index, DataGridItemPropertyBase item ) { - string itemName = item.Name; + Debug.Assert( ( index >= 0 ) && ( index <= m_collection.Count ) ); + Debug.Assert( item != null ); + Debug.Assert( !string.IsNullOrEmpty( item.Name ) ); + + var name = item.Name; + if( m_nameToItem.ContainsKey( name ) ) + throw new InvalidOperationException( "An item with the same name is already in the collection." ); + + if( item.ContainingCollection != null ) + throw new InvalidOperationException( "The item is already contained in a collection." ); + + item.IsNameSealed = true; - if( string.IsNullOrEmpty( itemName ) ) - throw new InvalidOperationException( "An attempt was made to add an item that does not have a name." ); + m_collection.Insert( index, item ); + m_nameToItem.Add( name, item ); - int count = this.Count; - for( int i = 0; i < count; i++ ) + var unboundItem = item as DataGridUnboundItemProperty; + if( unboundItem != null ) { - if( String.Equals( itemName, this[ i ].Name ) ) - throw new InvalidOperationException( "An attempt was made to add an item that has the same name (" + itemName + ") as another item currently contained in the collection." ); + m_unboundItems.Add( unboundItem ); } - item.ValueChanged += new EventHandler( DataGridItemProperty_ValueChanged ); - item.PropertyChanged += new PropertyChangedEventHandler( OnDataGridItemProperty_PropertyChanged ); - item.SetUnspecifiedPropertiesValues( this ); - item.Initialized = true; + item.AttachToContainingCollection( this ); + + this.OnInitializeItemProperty( item ); + this.RegisterEvents( item ); + + item.IsSealed = true; + } - if( item is DataGridUnboundItemProperty ) + private void RemoveItem( int index, DataGridItemPropertyBase item ) + { + Debug.Assert( ( index >= 0 ) && ( index < m_collection.Count ) ); + Debug.Assert( item != null ); + Debug.Assert( object.ReferenceEquals( item, m_collection[ index ] ) ); + + this.UnregisterEvents( item ); + + m_collection.RemoveAt( index ); + m_nameToItem.Remove( item.Name ); + + var unboundItem = item as DataGridUnboundItemProperty; + if( unboundItem != null ) { - m_unboundItemPropertyCount++; + m_unboundItems.Remove( unboundItem ); } - try + this.RemoveSynonym( item ); + this.ClearItem( item ); + } + + private void AddSynonym( DataGridItemPropertyBase item ) + { + Debug.Assert( item != null ); + + var synonym = item.Synonym; + if( string.IsNullOrEmpty( synonym ) ) + return; + + DataGridItemPropertyBase[] synonyms; + if( m_synonymToItem.TryGetValue( synonym, out synonyms ) ) { - base.InsertItem( index, item ); + Array.Resize( ref synonyms, synonyms.Length + 1 ); } - catch + else { - item.ValueChanged -= new EventHandler( DataGridItemProperty_ValueChanged ); - item.PropertyChanged -= new PropertyChangedEventHandler( OnDataGridItemProperty_PropertyChanged ); - item.Initialized = false; + Array.Resize( ref synonyms, 1 ); + } + + synonyms[ synonyms.Length - 1 ] = item; + m_synonymToItem[ synonym ] = synonyms; + } + + private void RemoveSynonym( DataGridItemPropertyBase item ) + { + Debug.Assert( item != null ); + + var synonym = item.Synonym; + if( string.IsNullOrEmpty( synonym ) ) + return; + + DataGridItemPropertyBase[] synonyms; + if( !m_synonymToItem.TryGetValue( synonym, out synonyms ) ) + return; + + var removeAt = Array.IndexOf( synonyms, item ); + Debug.Assert( removeAt >= 0 ); - if( item is DataGridUnboundItemProperty ) + if( removeAt < 0 ) + return; + + if( synonyms.Length > 1 ) + { + for( int i = removeAt + 1; i < synonyms.Length; i++ ) { - m_unboundItemPropertyCount--; + synonyms[ i - 1 ] = synonyms[ i ]; } - throw; + Array.Resize( ref synonyms, synonyms.Length - 1 ); + + m_synonymToItem[ synonym ] = synonyms; + } + else + { + m_synonymToItem.Remove( synonym ); } + } - item.FilterCriterionChanged += new EventHandler( DataGridItemProperty_FilterCriterionChanged ); + private void ClearItem( DataGridItemPropertyBase item ) + { + Debug.Assert( item != null ); + + item.IsNameSealed = false; + item.IsSealed = false; + item.DetachFromContainingCollection(); } - internal List DefaultItemProperties + private void RegisterEvents( DataGridItemPropertyBase item ) { - get + Debug.Assert( item != null ); + + item.PropertyChanged += new PropertyChangedEventHandler( this.OnItemPropertyChanged ); + item.ValueChanged += new EventHandler( this.OnItemValueChanged ); + + if( item.ItemPropertiesInternal != null ) { - return m_defaultItemProperties; + item.ItemPropertiesInternal.InitializeItemProperty += new EventHandler( this.OnItemInitializeItemProperty ); } - set + } + + private void UnregisterEvents( DataGridItemPropertyBase item ) + { + Debug.Assert( item != null ); + + item.PropertyChanged -= new PropertyChangedEventHandler( this.OnItemPropertyChanged ); + item.ValueChanged -= new EventHandler( this.OnItemValueChanged ); + + if( item.ItemPropertiesInternal != null ) { - if( m_defaultItemProperties == null ) - { - m_defaultItemProperties = value; - - //if the default item properties were just set... - //then go through all pre-existing DataGridItemProperty and try to give them the PropertyDescriptor, ValuePath or Title for matching default item property - if( m_itemType != null ) - { - //but only do it if the ItemType is set as well - foreach( DataGridItemPropertyBase itemProperty in this ) - { - itemProperty.SetUnspecifiedPropertiesValues( this ); - } - } - } + item.ItemPropertiesInternal.InitializeItemProperty -= new EventHandler( this.OnItemInitializeItemProperty ); } } - internal Type ItemType + private void OnItemPropertyChanged( object sender, PropertyChangedEventArgs e ) { - get + var item = ( DataGridItemPropertyBase )sender; + var propertyName = e.PropertyName; + + if( string.IsNullOrEmpty( e.PropertyName ) || ( propertyName == DataGridItemPropertyBase.GroupSortStatResultPropertyNamePropertyName ) ) { - return m_itemType; + this.OnItemPropertyGroupSortStatNameChanged(); } - set + + if( string.IsNullOrEmpty( e.PropertyName ) || ( propertyName == DataGridItemPropertyBase.ItemPropertiesInternalPropertyName ) ) + { + this.OnItemItemPropertiesInternalChanged( ( DataGridItemPropertyBase )sender ); + } + + if( string.IsNullOrEmpty( e.PropertyName ) || ( propertyName == DataGridItemPropertyBase.IsSealedPropertyName ) ) { - if( m_itemType == null ) + if( item.IsSealed ) { - m_itemType = value; - - //if the item type were just set... - //then go through all pre-existing DataGridItemProperty and try to give then the PropertyDescriptor, ValuePath or Title for matching default item property - if( m_defaultItemProperties != null ) - { - //but only do it if the DefaultItemProperties is set as well - foreach( DataGridItemPropertyBase itemProperty in this ) - { - itemProperty.SetUnspecifiedPropertiesValues( this ); - } - } + this.AddSynonym( item ); + } + else + { + this.RemoveSynonym( item ); } } } - internal void UnregisterDataGridItemPropertiesEvents() + private void OnItemValueChanged( object sender, DataGridItemPropertyBase.ValueChangedEventArgs e ) { - int count = this.Count; + this.RefreshUnboundItemProperty( e.Component ); + } - for( int i = 0; i < count; i++ ) - { - DataGridItemPropertyBase item = this[ i ]; + private void OnItemItemPropertiesInternalChanged( DataGridItemPropertyBase itemProperty ) + { + if( ( itemProperty == null ) || ( itemProperty.ItemPropertiesInternal == null ) ) + return; - item.FilterCriterionChanged -= this.DataGridItemProperty_FilterCriterionChanged; - item.ValueChanged -= this.DataGridItemProperty_ValueChanged; - item.PropertyChanged -= new PropertyChangedEventHandler( OnDataGridItemProperty_PropertyChanged ); - } + itemProperty.ItemPropertiesInternal.InitializeItemProperty += new EventHandler( this.OnItemInitializeItemProperty ); } - internal DataGridItemPropertyBase FindDefaultItemProperty( string name ) + private void OnItemInitializeItemProperty( object sender, InitializeItemPropertyEventArgs e ) { - if( m_defaultItemProperties != null ) - { - foreach( DataGridItemPropertyBase itemProperty in m_defaultItemProperties ) - { - if( string.Equals( itemProperty.Name, name ) ) - return itemProperty; - } - } + var itemProperties = sender as DataGridItemPropertyCollection; + if( itemProperties == null ) + return; - return null; + this.RelayInitializeItemProperty( e ); } - internal void RefreshUnboundItemProperty( object component ) + #region IList<> Members + + public DataGridItemPropertyBase this[ int index ] { - if( m_unboundItemPropertyCount > 0 ) + get { - if( this.IsUnboundItemPropertyInRefresh( component ) ) - return; + if( ( index < 0 ) || ( index >= m_collection.Count ) ) + throw new ArgumentOutOfRangeException( "index" ); - if( this.IsUnboundItemPropertyChangedSuspended( component ) ) - return; + return m_collection[ index ]; + } + set + { + if( ( index < 0 ) || ( index > m_collection.Count ) ) + throw new ArgumentOutOfRangeException( "index" ); - this.AddUnboundItemPropertyInRefresh( component ); - UnboundDataItem unboundDataItem; - UnboundDataItem.GetUnboundDataItemNode( component, out unboundDataItem ); + if( value == null ) + throw new ArgumentNullException( "value" ); - try + if( string.IsNullOrEmpty( value.Name ) ) + throw new ArgumentException( "The item must have a non empty name.", "value" ); + + if( index < m_collection.Count ) { - foreach( DataGridItemPropertyBase itemProperty in this ) - { - DataGridUnboundItemProperty unboundItemProperty = itemProperty as DataGridUnboundItemProperty; - - if( unboundItemProperty != null ) - { - unboundItemProperty.Refresh( unboundDataItem ); - } - } + var oldItem = m_collection[ index ]; + if( value == oldItem ) + return; + + this.ReplaceItemAndNotify( index, oldItem, value ); } - finally + else { - this.RemoveUnboundItemPropertyInRefresh( component ); + this.InsertItemAndNotify( index, value ); } } } - internal void SuspendUnboundItemPropertyChanged( object component ) + public int IndexOf( DataGridItemPropertyBase item ) + { + if( !this.Contains( item ) ) + return -1; + + return m_collection.IndexOf( item ); + } + + public void Insert( int index, DataGridItemPropertyBase item ) { - if( m_unboundItemPropertyChangedSuspended == null ) + if( ( index < 0 ) || ( index > m_collection.Count ) ) + throw new ArgumentOutOfRangeException( "index" ); + + if( item == null ) + throw new ArgumentNullException( "item" ); + + if( string.IsNullOrEmpty( item.Name ) ) + throw new ArgumentException( "The item must have a non empty name.", "item" ); + + this.InsertItemAndNotify( index, item ); + } + + public void RemoveAt( int index ) + { + if( ( index < 0 ) || ( index >= m_collection.Count ) ) + throw new ArgumentOutOfRangeException( "index" ); + + this.RemoveItemAndNotify( index, m_collection[ index ] ); + } + + #endregion + + #region IList Members + + bool IList.IsFixedSize + { + get { - m_unboundItemPropertyChangedSuspended = new Hashtable( 1 ); + return false; } + } - m_unboundItemPropertyChangedSuspended[ component ] = DBNull.Value; + bool IList.IsReadOnly + { + get + { + return ( ( ICollection )this ).IsReadOnly; + } } - internal void ResumeUnboundItemPropertyChanged( object component ) + object IList.this[ int index ] { - if( m_unboundItemPropertyChangedSuspended == null ) + get { - Debug.Assert( false, "Not suppose to resume when nothing is in the UnboundItemPropertyChangedSuspended list." ); - return; + return this[ index ]; } + set + { + this[ index ] = ( DataGridItemPropertyBase )value; + } + } + + int IList.Add( object value ) + { + var item = value as DataGridItemPropertyBase; + if( item == null ) + return -1; + + this.Add( item ); + + return m_collection.Count - 1; + } + + bool IList.Contains( object value ) + { + return this.Contains( value as DataGridItemPropertyBase ); + } + + int IList.IndexOf( object value ) + { + var item = value as DataGridItemPropertyBase; + if( !this.Contains( item ) ) + return -1; - m_unboundItemPropertyChangedSuspended.Remove( component ); + return m_collection.IndexOf( item ); + } + + void IList.Insert( int index, object value ) + { + this.Insert( index, ( DataGridItemPropertyBase )value ); + } + + void IList.Remove( object value ) + { + this.Remove( value as DataGridItemPropertyBase ); + } + + void IList.RemoveAt( int index ) + { + this.RemoveAt( index ); + } + + #endregion + + #region ICollection<> Members - if( m_unboundItemPropertyChangedSuspended.Count == 0 ) + bool ICollection.IsReadOnly + { + get { - m_unboundItemPropertyChangedSuspended = null; + return false; } + } - this.RefreshUnboundItemProperty( component ); + public void Add( DataGridItemPropertyBase item ) + { + this.Insert( m_collection.Count, item ); } - private bool IsUnboundItemPropertyChangedSuspended( object component ) + public void Clear() { - if( m_unboundItemPropertyChangedSuspended == null ) - return false; + if( m_collection.Count == 0 ) + return; + + var removedItems = m_collection.ToList(); + + m_collection.Clear(); + m_nameToItem.Clear(); + m_synonymToItem.Clear(); + m_unboundItems.Clear(); + + foreach( var item in removedItems ) + { + this.UnregisterEvents( item ); + this.ClearItem( item ); + } - return m_unboundItemPropertyChangedSuspended.Contains( component ); + this.OnPropertyChanged( DataGridItemPropertyCollection.CountPropertyName ); + this.OnPropertyChanged( DataGridItemPropertyCollection.ItemsPropertyName ); + this.OnCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Remove, removedItems ) ); } - private void DataGridItemProperty_FilterCriterionChanged( object sender, EventArgs e ) + public bool Contains( DataGridItemPropertyBase item ) { - if( this.FilterCriterionChanged != null ) - this.FilterCriterionChanged( this, EventArgs.Empty ); + if( item == null ) + return false; + + var name = item.Name; + if( string.IsNullOrEmpty( name ) ) + return false; + + DataGridItemPropertyBase stored; + if( !m_nameToItem.TryGetValue( name, out stored ) ) + return false; + + return ( item == stored ); } - private void DataGridItemProperty_ValueChanged( object sender, DataGridItemPropertyBase.ValueChangedEventArgs e ) + void ICollection.CopyTo( DataGridItemPropertyBase[] array, int index ) { - this.RefreshUnboundItemProperty( e.Component ); + m_collection.CopyTo( array, index ); } - private bool IsUnboundItemPropertyInRefresh( object component ) + public bool Remove( DataGridItemPropertyBase item ) { - if( m_unboundItemPropertyInRefresh == null ) + if( !this.Contains( item ) ) return false; - return m_unboundItemPropertyInRefresh.Contains( component ); + var index = m_collection.IndexOf( item ); + Debug.Assert( index >= 0 ); + + this.RemoveItemAndNotify( index, item ); + + return true; } - private void AddUnboundItemPropertyInRefresh( object component ) - { - if( m_unboundItemPropertyInRefresh == null ) - m_unboundItemPropertyInRefresh = new Hashtable( 1 ); + #endregion - object count = m_unboundItemPropertyInRefresh[ component ]; + #region ICollection Members - if( count == null ) + public int Count + { + get { - m_unboundItemPropertyInRefresh[ component ] = 1; + return m_collection.Count; } - else + } + + bool ICollection.IsSynchronized + { + get { - m_unboundItemPropertyInRefresh[ component ] = ( ( int )count ) + 1; + return false; } } - private void RemoveUnboundItemPropertyInRefresh( object component ) + object ICollection.SyncRoot { - if( m_unboundItemPropertyInRefresh == null ) + get { - Debug.Assert( false, "Not suppose to remove when nothing is in the UnboundItemPropertyInRefresh list." ); + return ( ( ICollection )m_collection ).SyncRoot; + } + } + + void ICollection.CopyTo( Array array, int index ) + { + ( ( ICollection )m_collection ).CopyTo( array, index ); + } + + #endregion + + #region IEnumerable<> Members + + public IEnumerator GetEnumerator() + { + return m_collection.GetEnumerator(); + } + + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + #endregion + + #region INotifyCollectionChanged Members + + public event NotifyCollectionChangedEventHandler CollectionChanged; + + private void OnCollectionChanged( NotifyCollectionChangedEventArgs e ) + { + if( e.Action == NotifyCollectionChangedAction.Reset ) + throw new NotSupportedException(); + + var handler = this.CollectionChanged; + if( handler == null ) return; + + lock( this.SyncRoot ) + { + if( m_deferCollectionChangedCount != 0 ) + { + m_deferCollectionChangedEventArgs = DataGridItemPropertyCollection.Combine( m_deferCollectionChangedEventArgs, e ); + return; + } } - object count = m_unboundItemPropertyInRefresh[ component ]; + handler.Invoke( this, e ); + } + + #endregion - if( count != null ) + #region INotifyPropertyChanged Members + + public event PropertyChangedEventHandler PropertyChanged; + + private void OnPropertyChanged( string propertyName ) + { + var handler = this.PropertyChanged; + if( handler == null ) + return; + + handler.Invoke( this, new PropertyChangedEventArgs( propertyName ) ); + } + + #endregion + + private int m_deferCollectionChangedCount; //0 + private NotifyCollectionChangedEventArgs m_deferCollectionChangedEventArgs; //null + + private readonly List m_collection = new List(); + private readonly Dictionary m_nameToItem = new Dictionary(); + private readonly Dictionary m_synonymToItem = new Dictionary(); + private readonly HashSet m_unboundItems = new HashSet(); + private readonly Dictionary m_dataItems = new Dictionary( 0 ); + + #region DeferState Private Class + + private sealed class DeferState : DeferredDisposableState + { + internal DeferState( DataGridItemPropertyCollection target ) { - int intCount = ( int )count; + Debug.Assert( target != null ); + m_target = target; + } - if( intCount <= 1 ) + protected override object SyncRoot + { + get { - if( m_unboundItemPropertyInRefresh.Count == 1 ) - { - m_unboundItemPropertyInRefresh = null; - } - else - { - m_unboundItemPropertyInRefresh.Remove( component ); - } + return m_target.SyncRoot; } - else + } + + protected override bool IsDeferred + { + get { - m_unboundItemPropertyInRefresh[ component ] = intCount - 1; + return ( m_target.m_deferCollectionChangedCount != 0 ); } } - } - #region ItemPropertyGroupSortStatNameChanged Event + protected override void Increment() + { + m_target.m_deferCollectionChangedCount++; + } - internal event EventHandler ItemPropertyGroupSortStatNameChanged; + protected override void Decrement() + { + m_target.m_deferCollectionChangedCount--; + } - private void OnDataGridItemProperty_PropertyChanged( object sender, PropertyChangedEventArgs e ) - { - if( e.PropertyName != "GroupSortStatResultPropertyName" ) - return; + protected override void OnDeferEnding( bool disposing ) + { + m_eventArgs = m_target.m_deferCollectionChangedEventArgs; + m_target.m_deferCollectionChangedEventArgs = null; - var handler = this.ItemPropertyGroupSortStatNameChanged; + base.OnDeferEnding( disposing ); + } - if( handler == null ) - return; + protected override void OnDeferEnded( bool disposing ) + { + if( m_eventArgs == null ) + return; - handler.Invoke( this, e ); + m_target.OnCollectionChanged( m_eventArgs ); + } + + private readonly DataGridItemPropertyCollection m_target; + private NotifyCollectionChangedEventArgs m_eventArgs; } #endregion - private List m_defaultItemProperties; - private Type m_itemType; - private int m_unboundItemPropertyCount; - private Hashtable m_unboundItemPropertyInRefresh; - private Hashtable m_unboundItemPropertyChangedSuspended; + #region State Private Struct + + private struct State + { + internal State( bool refreshing, bool suspended ) + { + this.Refreshing = refreshing; + this.Suspended = suspended; + } + + internal readonly bool Refreshing; + internal readonly bool Suspended; + } + + #endregion } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyMap.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyMap.cs new file mode 100644 index 00000000..c6874223 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyMap.cs @@ -0,0 +1,625 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Windows; +using Xceed.Utils.Wpf; + +namespace Xceed.Wpf.DataGrid +{ + internal sealed class DataGridItemPropertyMap : IWeakEventListener + { + #region MasterItemProperties Property + + internal DataGridItemPropertyCollection MasterItemProperties + { + get + { + return m_masterItemProperties; + } + set + { + if( value == m_masterItemProperties ) + return; + + using( this.DeferMappingChanged() ) + { + this.UnregisterItemProperties( m_masterItemProperties ); + this.UnmapItemProperties(); + + m_masterItemProperties = value; + + this.MapItemProperties(); + this.RegisterItemProperties( m_masterItemProperties ); + } + } + } + + private DataGridItemPropertyCollection m_masterItemProperties; + + #endregion + + #region DetailItemProperties Property + + internal DataGridItemPropertyCollection DetailItemProperties + { + get + { + return m_detailItemProperties; + } + set + { + if( value == m_detailItemProperties ) + return; + + using( this.DeferMappingChanged() ) + { + this.UnregisterItemProperties( m_detailItemProperties ); + this.UnmapItemProperties(); + + m_detailItemProperties = value; + + this.MapItemProperties(); + this.RegisterItemProperties( m_detailItemProperties ); + } + } + } + + private DataGridItemPropertyCollection m_detailItemProperties; + + #endregion + + #region IsMapping Property + + internal bool IsMapping + { + get + { + return ( m_masterItemProperties != null ) + && ( m_detailItemProperties != null ); + } + } + + #endregion + + #region MappingChanged Event + + internal event EventHandler MappingChanged; + + private void OnMappingChanged() + { + if( m_deferRaiseMappingChangedCount != 0 ) + { + m_raiseMappingChanged = true; + } + else + { + m_raiseMappingChanged = false; + + var handler = this.MappingChanged; + if( handler == null ) + return; + + handler.Invoke( this, EventArgs.Empty ); + } + } + + #endregion + + internal IDisposable DeferMappingChanged() + { + return new DeferredDisposable( new DeferMappingChangedEvent( this ) ); + } + + internal bool TryGetMasterItemProperty( DataGridItemPropertyBase detailItemProperty, out DataGridItemPropertyBase masterItemProperty ) + { + return DataGridItemPropertyMap.TryGetTargetItemProperty( m_detailToMaster, detailItemProperty, out masterItemProperty ); + } + + internal bool TryGetDetailItemProperty( DataGridItemPropertyBase masterItemProperty, out DataGridItemPropertyBase detailItemProperty ) + { + return DataGridItemPropertyMap.TryGetTargetItemProperty( m_masterToDetail, masterItemProperty, out detailItemProperty ); + } + + private static bool TryGetTargetItemProperty( Dictionary collection, DataGridItemPropertyBase sourceItemProperty, out DataGridItemPropertyBase targetItemProperty ) + { + if( ( collection != null ) && ( sourceItemProperty != null ) && collection.TryGetValue( sourceItemProperty, out targetItemProperty ) ) + return true; + + targetItemProperty = default( DataGridItemPropertyBase ); + + return false; + } + + private void RegisterItemProperties( DataGridItemPropertyCollection itemProperties ) + { + if( itemProperties == null ) + return; + + CollectionChangedEventManager.AddListener( itemProperties, this ); + + foreach( var itemProperty in itemProperties ) + { + this.RegisterItemProperty( itemProperty ); + } + } + + private void UnregisterItemProperties( DataGridItemPropertyCollection itemProperties ) + { + if( itemProperties == null ) + return; + + foreach( var itemProperty in itemProperties ) + { + this.UnregisterItemProperty( itemProperty ); + } + + CollectionChangedEventManager.RemoveListener( itemProperties, this ); + } + + private void RegisterItemProperty( DataGridItemPropertyBase itemProperty ) + { + if( itemProperty == null ) + return; + + if( !m_listeningToPropertyChanged.Add( itemProperty ) ) + return; + + PropertyChangedEventManager.AddListener( itemProperty, this, string.Empty ); + this.RegisterItemProperties( itemProperty.ItemPropertiesInternal ); + } + + private void UnregisterItemProperty( DataGridItemPropertyBase itemProperty ) + { + if( itemProperty == null ) + return; + + if( !m_listeningToPropertyChanged.Remove( itemProperty ) ) + return; + + this.UnregisterItemProperties( itemProperty.ItemPropertiesInternal ); + PropertyChangedEventManager.RemoveListener( itemProperty, this, string.Empty ); + } + + private void MapItemProperties() + { + this.MapItemProperties( m_masterItemProperties, m_detailItemProperties ); + } + + private void MapItemProperties( DataGridItemPropertyCollection masterItemProperties, DataGridItemPropertyCollection detailItemProperties ) + { + if( ( masterItemProperties == null ) || ( masterItemProperties.Count <= 0 ) ) + return; + + foreach( var masterItemProperty in masterItemProperties ) + { + this.MapMasterItemProperty( masterItemProperty ); + } + } + + private void MapItemProperties( DataGridItemPropertyBase masterItemProperty, DataGridItemPropertyBase detailItemProperty ) + { + if( ( masterItemProperty == null ) || ( detailItemProperty == null ) ) + return; + + DataGridItemPropertyBase mappedItemProperty; + if( m_masterToDetail.TryGetValue( masterItemProperty, out mappedItemProperty ) ) + { + if( mappedItemProperty == detailItemProperty ) + return; + + this.UnmapMasterItemProperty( masterItemProperty ); + } + + this.UnmapDetailItemProperty( detailItemProperty ); + + m_masterToDetail[ masterItemProperty ] = detailItemProperty; + m_detailToMaster[ detailItemProperty ] = masterItemProperty; + + this.OnMappingChanged(); + this.MapItemProperties( masterItemProperty.ItemPropertiesInternal, detailItemProperty.ItemPropertiesInternal ); + } + + private void MapMasterItemProperty( DataGridItemPropertyBase itemProperty ) + { + if( itemProperty == null ) + return; + + var collection = itemProperty.ContainingCollection; + if( collection == null ) + return; + + DataGridItemPropertyCollection mappedItemProperties; + DataGridItemPropertyBase mappedItemProperty; + + var owner = collection.Owner; + if( owner == null ) + { + Debug.Assert( collection == m_masterItemProperties ); + if( collection != m_masterItemProperties ) + return; + + mappedItemProperties = m_detailItemProperties; + } + else + { + if( !m_masterToDetail.TryGetValue( owner, out mappedItemProperty ) ) + return; + + mappedItemProperties = mappedItemProperty.ItemPropertiesInternal; + } + + if( mappedItemProperties == null ) + return; + + mappedItemProperty = mappedItemProperties.GetForSynonym( itemProperty.Name ); + + if( mappedItemProperty != null ) + { + this.MapItemProperties( itemProperty, mappedItemProperty ); + } + else + { + this.UnmapMasterItemProperty( itemProperty ); + } + } + + private void MapDetailItemProperty( DataGridItemPropertyBase itemProperty ) + { + if( itemProperty == null ) + return; + + var collection = itemProperty.ContainingCollection; + if( collection == null ) + return; + + DataGridItemPropertyCollection mappedItemProperties; + DataGridItemPropertyBase mappedItemProperty; + + var owner = collection.Owner; + if( owner == null ) + { + Debug.Assert( collection == m_detailItemProperties ); + if( collection != m_detailItemProperties ) + return; + + mappedItemProperties = m_masterItemProperties; + } + else + { + if( !m_detailToMaster.TryGetValue( owner, out mappedItemProperty ) ) + return; + + mappedItemProperties = mappedItemProperty.ItemPropertiesInternal; + } + + if( mappedItemProperties == null ) + return; + + mappedItemProperty = ( !string.IsNullOrEmpty( itemProperty.Synonym ) ) ? mappedItemProperties[ itemProperty.Synonym ] : null; + + if( mappedItemProperty != null ) + { + this.MapItemProperties( mappedItemProperty, itemProperty ); + } + else + { + this.UnmapDetailItemProperty( itemProperty ); + } + } + + private void UnmapItemProperties() + { + if( ( m_masterItemProperties == null ) || ( m_detailItemProperties == null ) ) + return; + + while( m_masterToDetail.Count > 0 ) + { + var entry = m_masterToDetail.First(); + + this.UnmapItemProperties( entry.Key, entry.Value, false ); + } + + Debug.Assert( m_masterToDetail.Count == 0 ); + Debug.Assert( m_detailToMaster.Count == 0 ); + + while( m_detailToMaster.Count > 0 ) + { + var entry = m_detailToMaster.First(); + + this.UnmapItemProperties( entry.Value, entry.Key, false ); + } + + m_masterToDetail.Clear(); + m_detailToMaster.Clear(); + } + + private void UnmapItemProperties( DataGridItemPropertyBase masterItemProperty, DataGridItemPropertyBase detailItemProperty, bool recursive ) + { + if( ( masterItemProperty == null ) || ( detailItemProperty == null ) ) + return; + + DataGridItemPropertyBase mappedItemProperty; + if( !m_masterToDetail.TryGetValue( masterItemProperty, out mappedItemProperty ) || ( mappedItemProperty != detailItemProperty ) ) + throw new InvalidOperationException(); + + if( !m_detailToMaster.TryGetValue( detailItemProperty, out mappedItemProperty ) || ( mappedItemProperty != masterItemProperty ) ) + throw new InvalidOperationException(); + + m_masterToDetail.Remove( masterItemProperty ); + m_detailToMaster.Remove( detailItemProperty ); + + this.OnMappingChanged(); + + if( recursive ) + { + this.UnmapMasterItemProperties( masterItemProperty.ItemPropertiesInternal ); + this.UnmapDetailItemProperties( detailItemProperty.ItemPropertiesInternal ); + } + } + + private void UnmapMasterItemProperties( DataGridItemPropertyCollection itemProperties ) + { + if( itemProperties == null ) + return; + + foreach( var itemProperty in itemProperties ) + { + this.UnmapMasterItemProperty( itemProperty ); + } + } + + private void UnmapDetailItemProperties( DataGridItemPropertyCollection itemProperties ) + { + if( itemProperties == null ) + return; + + foreach( var itemProperty in itemProperties ) + { + this.UnmapDetailItemProperty( itemProperty ); + } + } + + private void UnmapMasterItemProperty( DataGridItemPropertyBase itemProperty ) + { + if( itemProperty == null ) + return; + + DataGridItemPropertyBase mappedItemProperty; + if( !m_masterToDetail.TryGetValue( itemProperty, out mappedItemProperty ) ) + return; + + Debug.Assert( mappedItemProperty != null ); + + this.UnmapItemProperties( itemProperty, mappedItemProperty, true ); + } + + private void UnmapDetailItemProperty( DataGridItemPropertyBase itemProperty ) + { + if( itemProperty == null ) + return; + + DataGridItemPropertyBase mappedItemProperty; + if( !m_detailToMaster.TryGetValue( itemProperty, out mappedItemProperty ) ) + return; + + Debug.Assert( mappedItemProperty != null ); + + this.UnmapItemProperties( mappedItemProperty, itemProperty, true ); + } + + private void OnItemPropertyCollectionChanged( DataGridItemPropertyCollection collection, NotifyCollectionChangedEventArgs e ) + { + var rootCollection = ItemsSourceHelper.GetRootCollection( collection ); + if( rootCollection == null ) + return; + + if( rootCollection == m_masterItemProperties ) + { + if( e.Action == NotifyCollectionChangedAction.Reset ) + throw new NotSupportedException(); + + if( e.Action == NotifyCollectionChangedAction.Move ) + return; + + using( this.DeferMappingChanged() ) + { + if( e.OldItems != null ) + { + foreach( DataGridItemPropertyBase itemProperty in e.OldItems ) + { + this.UnregisterItemProperty( itemProperty ); + this.UnmapMasterItemProperty( itemProperty ); + } + } + + if( e.NewItems != null ) + { + foreach( DataGridItemPropertyBase itemProperty in e.NewItems ) + { + this.RegisterItemProperty( itemProperty ); + this.MapMasterItemProperty( itemProperty ); + } + } + } + } + else if( rootCollection == m_detailItemProperties ) + { + if( e.Action == NotifyCollectionChangedAction.Reset ) + throw new NotSupportedException(); + + if( e.Action == NotifyCollectionChangedAction.Move ) + return; + + using( this.DeferMappingChanged() ) + { + if( e.OldItems != null ) + { + foreach( DataGridItemPropertyBase itemProperty in e.OldItems ) + { + this.UnregisterItemProperty( itemProperty ); + this.UnmapDetailItemProperty( itemProperty ); + } + } + + if( e.NewItems != null ) + { + foreach( DataGridItemPropertyBase itemProperty in e.NewItems ) + { + this.RegisterItemProperty( itemProperty ); + this.MapDetailItemProperty( itemProperty ); + } + } + } + } + else + { + Debug.Fail( "The collection should have been either for the master or the detail item properties." ); + CollectionChangedEventManager.RemoveListener( collection, this ); + } + } + + private void OnItemPropertyPropertyChanged( DataGridItemPropertyBase itemProperty, PropertyChangedEventArgs e ) + { + var rootCollection = ItemsSourceHelper.GetRootCollection( itemProperty ); + if( rootCollection == null ) + return; + + using( this.DeferMappingChanged() ) + { + if( string.IsNullOrEmpty( e.PropertyName ) || ( e.PropertyName == DataGridItemPropertyBase.SynonymPropertyName ) ) + { + if( rootCollection == m_detailItemProperties ) + { + this.MapDetailItemProperty( itemProperty ); + } + } + + if( string.IsNullOrEmpty( e.PropertyName ) || ( e.PropertyName == DataGridItemPropertyBase.ItemPropertiesInternalPropertyName ) ) + { + var itemProperties = itemProperty.ItemPropertiesInternal; + if( itemProperties != null ) + { + this.UnregisterItemProperties( itemProperties ); + this.RegisterItemProperties( itemProperties ); + + if( rootCollection == m_masterItemProperties ) + { + foreach( var childItemProperty in itemProperties ) + { + this.MapMasterItemProperty( childItemProperty ); + } + } + else if( rootCollection == m_detailItemProperties ) + { + foreach( var childItemProperty in itemProperties ) + { + this.MapDetailItemProperty( childItemProperty ); + } + } + } + } + } + } + + #region IWeakEventListener Members + + bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) + { + if( managerType == typeof( CollectionChangedEventManager ) ) + { + this.OnItemPropertyCollectionChanged( ( DataGridItemPropertyCollection )sender, ( NotifyCollectionChangedEventArgs )e ); + } + else if( managerType == typeof( PropertyChangedEventManager ) ) + { + this.OnItemPropertyPropertyChanged( ( DataGridItemPropertyBase )sender, ( PropertyChangedEventArgs )e ); + } + else + { + return false; + } + + return true; + } + + #endregion + + private readonly Dictionary m_masterToDetail = new Dictionary(); + private readonly Dictionary m_detailToMaster = new Dictionary(); + private readonly HashSet m_listeningToPropertyChanged = new HashSet(); + private int m_deferRaiseMappingChangedCount; + private bool m_raiseMappingChanged; //false + + #region DeferMappingChangedEvent Private Class + + private sealed class DeferMappingChangedEvent : DeferredDisposableState + { + internal DeferMappingChangedEvent( DataGridItemPropertyMap target ) + { + if( target == null ) + throw new ArgumentNullException( "target" ); + + m_target = target; + } + + protected override object SyncRoot + { + get + { + return m_target.m_listeningToPropertyChanged; + } + } + + protected override bool IsDeferred + { + get + { + return ( m_target.m_deferRaiseMappingChangedCount != 0 ); + } + } + + protected override void Increment() + { + m_target.m_deferRaiseMappingChangedCount++; + } + + protected override void Decrement() + { + m_target.m_deferRaiseMappingChangedCount--; + } + + protected override void OnDeferEnded( bool disposing ) + { + if( !disposing ) + return; + + if( m_target.m_raiseMappingChanged ) + { + m_target.OnMappingChanged(); + } + } + + private readonly DataGridItemPropertyMap m_target; + } + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyMapHelper.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyMapHelper.cs new file mode 100644 index 00000000..1a6e4563 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyMapHelper.cs @@ -0,0 +1,118 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + + +namespace Xceed.Wpf.DataGrid +{ + internal static class DataGridItemPropertyMapHelper + { + internal static bool TryGetMasterColumnName( DataGridItemPropertyMap itemPropertyMap, string detailColumnName, out string masterColumnName ) + { + masterColumnName = default( string ); + + if( itemPropertyMap == null ) + return false; + + var detailItemProperty = ItemsSourceHelper.GetItemPropertyFromProperty( itemPropertyMap.DetailItemProperties, detailColumnName ); + if( detailItemProperty == null ) + return false; + + DataGridItemPropertyBase masterItemProperty; + if( !itemPropertyMap.TryGetMasterItemProperty( detailItemProperty, out masterItemProperty ) ) + return false; + + masterColumnName = PropertyRouteParser.Parse( masterItemProperty ); + + return !string.IsNullOrEmpty( masterColumnName ); + } + + internal static bool TryGetDetailColumnName( DataGridItemPropertyMap itemPropertyMap, string masterColumnName, out string detailColumnName ) + { + detailColumnName = default( string ); + + if( itemPropertyMap == null ) + return false; + + var masterItemProperty = ItemsSourceHelper.GetItemPropertyFromProperty( itemPropertyMap.MasterItemProperties, masterColumnName ); + if( masterItemProperty == null ) + return false; + + DataGridItemPropertyBase detailItemProperty; + if( !itemPropertyMap.TryGetDetailItemProperty( masterItemProperty, out detailItemProperty ) ) + return false; + + detailColumnName = PropertyRouteParser.Parse( detailItemProperty ); + + return !string.IsNullOrEmpty( detailColumnName ); + } + + internal static bool TryGetMasterColumn( DataGridContext detailContext, ColumnBase detailColumn, out ColumnBase masterColumn ) + { + if( detailContext != null ) + { + var masterContext = detailContext.RootDataGridContext; + if( masterContext != null ) + return DataGridItemPropertyMapHelper.TryGetMasterColumn( detailContext.ItemPropertyMap, masterContext.Columns, detailColumn, out masterColumn ); + } + + masterColumn = default( ColumnBase ); + + return false; + } + + internal static bool TryGetDetailColumn( DataGridContext detailContext, ColumnBase masterColumn, out ColumnBase detailColumn ) + { + if( detailContext != null ) + return DataGridItemPropertyMapHelper.TryGetDetailColumn( detailContext.ItemPropertyMap, detailContext.Columns, masterColumn, out detailColumn ); + + detailColumn = default( ColumnBase ); + + return false; + } + + internal static bool TryGetMasterColumn( DataGridItemPropertyMap itemPropertyMap, ColumnCollection masterColumns, ColumnBase detailColumn, out ColumnBase masterColumn ) + { + masterColumn = default( ColumnBase ); + + if( ( masterColumns == null ) || ( detailColumn == null ) ) + return false; + + string masterColumnName; + if( !DataGridItemPropertyMapHelper.TryGetMasterColumnName( itemPropertyMap, detailColumn.FieldName, out masterColumnName ) ) + return false; + + masterColumn = masterColumns[ masterColumnName ]; + + return ( masterColumn != null ); + } + + internal static bool TryGetDetailColumn( DataGridItemPropertyMap itemPropertyMap, ColumnCollection detailColumns, ColumnBase masterColumn, out ColumnBase detailColumn ) + { + detailColumn = default( ColumnBase ); + + if( ( detailColumns == null ) || ( masterColumn == null ) ) + return false; + + string detailColumnName; + if( !DataGridItemPropertyMapHelper.TryGetDetailColumnName( itemPropertyMap, masterColumn.FieldName, out detailColumnName ) ) + return false; + + detailColumn = detailColumns[ detailColumnName ]; + + return ( detailColumn != null ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyRoute.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyRoute.cs new file mode 100644 index 00000000..1e094a81 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridItemPropertyRoute.cs @@ -0,0 +1,97 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Diagnostics; + +namespace Xceed.Wpf.DataGrid +{ + internal sealed class DataGridItemPropertyRoute + { + private DataGridItemPropertyRoute( DataGridItemPropertyBase itemProperty ) + : this( itemProperty, null ) + { + } + + private DataGridItemPropertyRoute( DataGridItemPropertyBase itemProperty, DataGridItemPropertyRoute parent ) + { + Debug.Assert( itemProperty != null ); + + m_itemProperty = itemProperty; + m_parent = parent; + } + + #region Current Property + + internal DataGridItemPropertyBase Current + { + get + { + return m_itemProperty; + } + } + + private readonly DataGridItemPropertyBase m_itemProperty; + + #endregion + + #region Parent Property + + internal DataGridItemPropertyRoute Parent + { + get + { + return m_parent; + } + } + + private readonly DataGridItemPropertyRoute m_parent; + + #endregion + + internal static DataGridItemPropertyRoute Create( DataGridItemPropertyBase itemProperty ) + { + if( itemProperty == null ) + return null; + + var collection = itemProperty.ContainingCollection; + if( collection == null ) + return new DataGridItemPropertyRoute( itemProperty ); + + return new DataGridItemPropertyRoute( + itemProperty, + DataGridItemPropertyRoute.Create( collection.Owner ) ); + } + + internal static DataGridItemPropertyRoute Combine( DataGridItemPropertyBase itemProperty, DataGridItemPropertyRoute ancestors ) + { + if( itemProperty == null ) + return ancestors; + + if( ancestors == null ) + return DataGridItemPropertyRoute.Create( itemProperty ); + + var collection = itemProperty.ContainingCollection; + if( collection == null ) + throw new InvalidOperationException(); + + if( collection.Owner != ancestors.Current ) + throw new InvalidOperationException(); + + return new DataGridItemPropertyRoute( itemProperty, ancestors ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridLINQPageManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridLINQPageManager.cs index dd240e68..4505d0ec 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridLINQPageManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridLINQPageManager.cs @@ -150,7 +150,7 @@ namespace Xceed.Wpf.DataGrid try { if( items.Count() != requestedItemCount ) - throw new InvalidOperationException( "TODODOC : The number of non-null items return by the source must be equal to the provided item count" ); + throw new InvalidOperationException( "The number of non-null items returned by the source must be equal to the provided item count." ); } catch { diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridUnboundItemProperty.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridUnboundItemProperty.cs index 38942c0c..abf7aa6a 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridUnboundItemProperty.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridUnboundItemProperty.cs @@ -15,12 +15,12 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.ComponentModel; +using System.Diagnostics; namespace Xceed.Wpf.DataGrid { + [DebuggerDisplay( "Name = {Name}" )] public class DataGridUnboundItemProperty : DataGridItemPropertyBase { public DataGridUnboundItemProperty() @@ -35,7 +35,7 @@ namespace Xceed.Wpf.DataGrid if( dataType == null ) throw new ArgumentNullException( "dataType" ); - this.Initialize( name, null, dataType, null, null, null ); + this.Initialize( name, null, dataType, null, null, null, null ); } public DataGridUnboundItemProperty( string name, Type dataType, bool isReadOnly ) @@ -46,7 +46,7 @@ namespace Xceed.Wpf.DataGrid if( dataType == null ) throw new ArgumentNullException( "dataType" ); - this.Initialize( name, null, dataType, isReadOnly, null, null ); + this.Initialize( name, null, dataType, isReadOnly, null, null, null ); } public DataGridUnboundItemProperty( string name, Type dataType, bool isReadOnly, bool overrideReadOnlyForInsertion ) @@ -57,24 +57,15 @@ namespace Xceed.Wpf.DataGrid if( dataType == null ) throw new ArgumentNullException( "dataType" ); - this.Initialize( name, null, dataType, isReadOnly, overrideReadOnlyForInsertion, null ); + this.Initialize( name, null, dataType, isReadOnly, overrideReadOnlyForInsertion, null, null ); } + [Browsable( false )] + [EditorBrowsable( EditorBrowsableState.Never )] + [Obsolete( "This constructor is obsolete and should no longer be used.", true )] protected DataGridUnboundItemProperty( DataGridUnboundItemProperty template ) - : base( template ) { - this.QueryValue += template.QueryValue; - this.CommittingValue += template.CommittingValue; - } - - public override object Clone() - { - Type type = this.GetType(); - - if( type == typeof( DataGridUnboundItemProperty ) ) - return new DataGridUnboundItemProperty( this ); - - return base.Clone(); + throw new NotSupportedException(); } public event EventHandler QueryValue; @@ -82,21 +73,23 @@ namespace Xceed.Wpf.DataGrid protected override object GetValueCore( object component ) { - if( this.QueryValue != null ) - { - DataGridItemPropertyQueryValueEventArgs gettingValueEventArgs = new DataGridItemPropertyQueryValueEventArgs( component ); - this.QueryValue( this, gettingValueEventArgs ); - return gettingValueEventArgs.Value; - } + var handler = this.QueryValue; + if( handler == null ) + return null; + + var e = new DataGridItemPropertyQueryValueEventArgs( component ); + + handler.Invoke( this, e ); - return null; + return e.Value; } protected override void SetValueCore( object component, object value ) { - if( this.CommittingValue != null ) + var handler = this.CommittingValue; + if( handler != null ) { - this.CommittingValue( this, new DataGridItemPropertyCommittingValueEventArgs( component, value ) ); + handler.Invoke( this, new DataGridItemPropertyCommittingValueEventArgs( component, value ) ); } base.SetValueCore( component, value ); @@ -104,20 +97,20 @@ namespace Xceed.Wpf.DataGrid internal void Refresh( object component ) { - PropertyDescriptorFromItemPropertyBase propertyDescriptor = this.GetPropertyDescriptorForBinding(); - + var propertyDescriptor = this.GetPropertyDescriptorForBinding(); if( propertyDescriptor == null ) return; propertyDescriptor.RaiseValueChanged( component ); } - internal override void SetUnspecifiedPropertiesValues( DataGridItemPropertyCollection itemPropertyCollection ) + internal override void SetUnspecifiedPropertiesValues( + PropertyDescription description, + Type itemType, + bool defaultItemPropertiesCreated ) { if( this.DataType == null ) - { throw new InvalidOperationException( "An attempt was made to add an item without specifying its data type." ); - } if( string.IsNullOrEmpty( this.Title ) ) { diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionView.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionView.cs index 4c68ec3d..17d68113 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionView.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionView.cs @@ -138,20 +138,6 @@ namespace Xceed.Wpf.DataGrid source.OnQueryItems( e ); } - - internal event EventHandler QueryAutoFilterDistinctValues; - - internal void OnQueryAutoFilterDistinctValues( QueryAutoFilterDistinctValuesEventArgs e ) - { - if( this.QueryAutoFilterDistinctValues != null ) - this.QueryAutoFilterDistinctValues( this, e ); - - DataGridVirtualizingCollectionViewSource source = this.ParentCollectionViewSourceBase as DataGridVirtualizingCollectionViewSource; - - if( source != null ) - source.OnQueryAutoFilterDistinctValues( e ); - } - #endregion DATA VIRTUALIZATION internal override IEnumerator GetVirtualEnumerator() @@ -159,48 +145,6 @@ namespace Xceed.Wpf.DataGrid return ( ( DataGridVirtualizingCollectionViewGroupRoot )this.RootGroup ).GetVirtualPageManager().GetEnumerator(); } - internal override void RefreshDistinctValuesForField( DataGridItemPropertyBase dataGridItemProperty ) - { - if( dataGridItemProperty == null ) - return; - - if( dataGridItemProperty.CalculateDistinctValues == false ) - return; - - // List containing current column distinct values - HashSet currentColumnDistinctValues = new HashSet(); - - ReadOnlyObservableHashList readOnlyColumnDistinctValues = null; - - // If the key is not set in DistinctValues yet, do not calculate distinct values for this field - if( !( ( DistinctValuesDictionary )this.DistinctValues ).InternalTryGetValue( dataGridItemProperty.Name, out readOnlyColumnDistinctValues ) ) - return; - - ObservableHashList columnDistinctValues = readOnlyColumnDistinctValues.InnerObservableHashList; - - // We use the DistinctValuesSortComparer if present, else the SortComparer for the DataGridItemProperty, else, - // the Comparer used is the one of the base class. - IComparer distinctValuesSortComparer = dataGridItemProperty.DistinctValuesSortComparer; - - if( distinctValuesSortComparer == null ) - distinctValuesSortComparer = dataGridItemProperty.SortComparer; - - using( columnDistinctValues.DeferINotifyCollectionChanged() ) - { - QueryAutoFilterDistinctValuesEventArgs e = new QueryAutoFilterDistinctValuesEventArgs( dataGridItemProperty ); - this.OnQueryAutoFilterDistinctValues( e ); - - foreach( object distinctValue in e.DistinctValues ) - { - // Compute current value to be able to remove unused values - currentColumnDistinctValues.Add( distinctValue ); - } - - DataGridCollectionViewBase.RemoveUnusedDistinctValues( - distinctValuesSortComparer, currentColumnDistinctValues, columnDistinctValues, null ); - } - } - internal override DataGridVirtualizingCollectionViewGroupBase CreateNewRootGroup() { bool rootIsBottomLevel = ( this.GroupDescriptions == null ) ? true : ( this.GroupDescriptions.Count == 0 ); diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewBase.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewBase.cs index 33d4d67e..81ba31c9 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewBase.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewBase.cs @@ -38,7 +38,9 @@ namespace Xceed.Wpf.DataGrid : base( sourceModel, null, itemType, autoCreateItemProperties, false, false ) { if( itemType == null ) + { itemType = typeof( object ); + } if( pageSize < 1 ) throw new ArgumentOutOfRangeException( "pageSize", pageSize, "pageSize must be greater than zero." ); @@ -47,7 +49,9 @@ namespace Xceed.Wpf.DataGrid throw new ArgumentOutOfRangeException( "maxRealizedItemCount", maxRealizedItemCount, "maxRealizedItemCount must be greater than zero." ); if( maxRealizedItemCount < pageSize ) + { maxRealizedItemCount = pageSize; + } m_pageSize = pageSize; m_maxRealizedItemCount = maxRealizedItemCount; @@ -62,7 +66,7 @@ namespace Xceed.Wpf.DataGrid throw new NotImplementedException(); } - #endregion CONSTRUCTORS + #endregion #region CollectionView Members @@ -70,8 +74,7 @@ namespace Xceed.Wpf.DataGrid { get { - bool canGroup = true; - return canGroup; + return true; } } @@ -308,10 +311,6 @@ namespace Xceed.Wpf.DataGrid private void ResetDistinctValues() { - DistinctValuesDictionary distinctValues = this.DistinctValues as DistinctValuesDictionary; - - if( distinctValues != null ) - distinctValues.InternalClear(); } #endregion @@ -507,8 +506,7 @@ namespace Xceed.Wpf.DataGrid if( currentAddItem == null ) return; - DataGridCommittingNewItemEventArgs committingNewItemEventArgs = - new DataGridCommittingNewItemEventArgs( this, currentAddItem, false ); + DataGridCommittingNewItemEventArgs committingNewItemEventArgs = new DataGridCommittingNewItemEventArgs( this, currentAddItem, false ); this.RootDataGridCollectionViewBase.OnCommittingNewItem( committingNewItemEventArgs ); @@ -525,6 +523,51 @@ namespace Xceed.Wpf.DataGrid this.ExecuteOrQueueSourceItemOperation( new DeferredOperation( DeferredOperation.DeferredOperationAction.Refresh, -1, null ) ); } + public override bool MoveCurrentTo( object item ) + { + m_canSynchronizeSelectionWithCurrent = true; + bool ret = base.MoveCurrentTo( item ); + m_canSynchronizeSelectionWithCurrent = false; + + return ret; + } + + public override bool MoveCurrentToFirst() + { + m_canSynchronizeSelectionWithCurrent = true; + bool ret = base.MoveCurrentToFirst(); + m_canSynchronizeSelectionWithCurrent = false; + + return ret; + } + + public override bool MoveCurrentToLast() + { + m_canSynchronizeSelectionWithCurrent = true; + bool ret = base.MoveCurrentToLast(); + m_canSynchronizeSelectionWithCurrent = false; + + return ret; + } + + public override bool MoveCurrentToNext() + { + m_canSynchronizeSelectionWithCurrent = true; + bool ret = base.MoveCurrentToNext(); + m_canSynchronizeSelectionWithCurrent = false; + + return ret; + } + + public override bool MoveCurrentToPrevious() + { + m_canSynchronizeSelectionWithCurrent = true; + bool ret = base.MoveCurrentToPrevious(); + m_canSynchronizeSelectionWithCurrent = false; + + return ret; + } + #endregion PUBLIC METHODS internal override void SetCurrentItemAndPositionCore( object currentItem, int currentPosition, bool isCurrentBeforeFirst, bool isCurrentAfterLast ) @@ -673,17 +716,20 @@ namespace Xceed.Wpf.DataGrid } } + internal bool CanSynchronizeSelectionWithCurrent + { + get + { + return m_canSynchronizeSelectionWithCurrent; + } + } + #endregion INTERNAL PROPERTIES #region INTERNAL METHODS internal abstract DataGridVirtualizingCollectionViewGroupBase CreateNewRootGroup(); - internal override bool CanCreateDetailDescriptions() - { - return false; - } - internal override void OnBeginningEdit( DataGridItemCancelEventArgs e ) { object item = e.Item; @@ -702,24 +748,24 @@ namespace Xceed.Wpf.DataGrid internal override void OnEditBegun( DataGridItemEventArgs e ) { - object item = e.Item; - - DataGridPageManagerBase pageManager = this.RootGroup.GetVirtualPageManager(); + var item = e.Item; + var pageManager = this.RootGroup.GetVirtualPageManager(); if( !pageManager.IsItemDirty( item ) ) { // First time we enter edit on this item. - DataGridItemPropertyCollection itemProperties = this.ItemProperties; - int count = itemProperties.Count; + var itemProperties = this.ItemProperties; + var count = itemProperties.Count; - string[] propertyNames = new string[ count ]; - object[] cachedValues = new object[ count ]; + var propertyNames = new string[ count ]; + var cachedValues = new object[ count ]; for( int i = 0; i < count; i++ ) { - DataGridItemPropertyBase itemProperty = itemProperties[ i ]; - propertyNames[ i ] = itemProperty.Name; - cachedValues[ i ] = itemProperty.GetValue( item ); + var itemProperty = itemProperties[ i ]; + + propertyNames[ i ] = PropertyRouteParser.Parse( itemProperty ); + cachedValues[ i ] = ItemsSourceHelper.GetValueFromItemProperty( itemProperty, item ); } // Cache the values of the never edited before row. This will help the developer find the corresponding row @@ -732,23 +778,22 @@ namespace Xceed.Wpf.DataGrid internal override void OnEditCommitted( DataGridItemEventArgs e ) { - object item = e.Item; - - DataGridPageManagerBase pageManager = this.RootGroup.GetVirtualPageManager(); + var item = e.Item; + var pageManager = this.RootGroup.GetVirtualPageManager(); // Compare cached values with current values. If they are the same, we can clear the old values which in turn will // make the item non dirty. - bool clearIsDirty = true; + var clearIsDirty = true; - VirtualizedItemValueCollection cachedValues = pageManager.GetCachedValuesForItem( item ); + var cachedValues = pageManager.GetCachedValuesForItem( item ); Debug.Assert( cachedValues != null ); - DataGridItemPropertyCollection itemProperties = this.ItemProperties; + var itemProperties = this.ItemProperties; - foreach( DataGridItemPropertyBase itemProperty in itemProperties ) + foreach( var itemProperty in itemProperties ) { - object currentValue = itemProperty.GetValue( item ); + var currentValue = ItemsSourceHelper.GetValueFromItemProperty( itemProperty, item ); if( !( object.Equals( currentValue, cachedValues[ itemProperty.Name ] ) ) ) { @@ -772,24 +817,24 @@ namespace Xceed.Wpf.DataGrid internal override void OnEditCanceled( DataGridItemEventArgs e ) { - object item = e.Item; - - DataGridPageManagerBase pageManager = this.RootGroup.GetVirtualPageManager(); + var item = e.Item; + var pageManager = this.RootGroup.GetVirtualPageManager(); // Compare cached values with current values. If they are the same, we can clear the old values which in turn will // make the item non dirty. - bool clearIsDirty = true; + var clearIsDirty = true; - VirtualizedItemValueCollection cachedValues = pageManager.GetCachedValuesForItem( item ); + var cachedValues = pageManager.GetCachedValuesForItem( item ); Debug.Assert( cachedValues != null ); - DataGridItemPropertyCollection itemProperties = this.ItemProperties; - foreach( DataGridItemPropertyBase itemProperty in itemProperties ) + var itemProperties = this.ItemProperties; + + foreach( var itemProperty in itemProperties ) { - object currentValue = itemProperty.GetValue( item ); + var currentValue = ItemsSourceHelper.GetValueFromItemProperty( itemProperty, item ); - if( !( object.Equals( currentValue, cachedValues[ itemProperty.Name ] ) ) ) + if( !( object.Equals( currentValue, cachedValues[ PropertyRouteParser.Parse( itemProperty ) ] ) ) ) { clearIsDirty = false; break; @@ -797,7 +842,9 @@ namespace Xceed.Wpf.DataGrid } if( clearIsDirty ) + { pageManager.ClearCachedValuesForItem( item ); + } base.OnEditCanceled( e ); } @@ -836,6 +883,8 @@ namespace Xceed.Wpf.DataGrid private object m_connectionError; private DataGridConnectionState m_connectionState; + private bool m_canSynchronizeSelectionWithCurrent; + #endregion PRIVATE FIELDS diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewGroup.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewGroup.cs index 46fba19b..95c64d4f 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewGroup.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewGroup.cs @@ -14,46 +14,39 @@ ***********************************************************************************/ -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.ComponentModel; using System.Collections.ObjectModel; -using System.Collections; -using System.Windows.Data; +using System.ComponentModel; using System.Diagnostics; -using System.Windows.Documents; -using System.Collections.Specialized; using System.Windows; namespace Xceed.Wpf.DataGrid { internal class DataGridVirtualizingCollectionViewGroup : DataGridVirtualizingCollectionViewGroupBase, IWeakEventListener { - #region STATIC MEMBERS - private static List EmptyDataGridInfoList = new List( 0 ); - #endregion STATIC MEMBERS - - - #region CONSTRUCTORS - - internal DataGridVirtualizingCollectionViewGroup( - object name, - int initialItemsCount, - int startGlobalIndex, - DataGridVirtualizingCollectionViewGroup parent, - int level, - bool isBottomLevel ) + internal DataGridVirtualizingCollectionViewGroup( object name, int initialItemsCount, int startGlobalIndex, DataGridVirtualizingCollectionViewGroup parent, int level, bool isBottomLevel ) : base( name, initialItemsCount, startGlobalIndex, parent, level, isBottomLevel ) { } - #endregion CONSTRUCTORS + #region GroupPath Property + + internal List GroupPath + { + get + { + if( m_groupPath == null ) + { + m_groupPath = this.BuildGroupPath(); + } + + return m_groupPath; + } + } - #region DATA VIRTUALIZATION + #endregion internal override int QueryItemCount() { @@ -79,8 +72,7 @@ namespace Xceed.Wpf.DataGrid object subGroupName = subGroupInfos[ i ].Name; int subGroupItemCount = subGroupInfos[ i ].ItemCount; - subCollectionViewGroupList.Add( - new DataGridVirtualizingCollectionViewGroup( subGroupName, subGroupItemCount, runningCount, this, nextLevel, nextLevelIsBottom ) ); + subCollectionViewGroupList.Add( new DataGridVirtualizingCollectionViewGroup( subGroupName, subGroupItemCount, runningCount, this, nextLevel, nextLevelIsBottom ) ); runningCount += subGroupItemCount; } @@ -88,27 +80,6 @@ namespace Xceed.Wpf.DataGrid return subCollectionViewGroupList; } - #endregion DATA VIRTUALIZATION - - - #region INTERNAL PROPERTIES - - internal List GroupPath - { - get - { - if( m_groupPath == null ) - m_groupPath = this.BuildGroupPath(); - - return m_groupPath; - } - } - - #endregion INTERNAL PROPERTIES - - - #region PRIVATE METHODS - private List BuildGroupPath() { DataGridVirtualizingCollectionViewGroup parent = this.Parent as DataGridVirtualizingCollectionViewGroup; @@ -129,17 +100,13 @@ namespace Xceed.Wpf.DataGrid Debug.Assert( groupDescriptions.Count > level ); if( groupDescriptions.Count > level ) + { groupPath.Add( new DataGridGroupInfo( groupDescriptions[ level ], this ) ); + } return groupPath; } - #endregion PRIVATE METHODS - - #region PRIVATE FIELDS - private List m_groupPath; - - #endregion PRIVATE FIELDS } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewGroupBase.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewGroupBase.cs index bb2b4b55..bdad311d 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewGroupBase.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewGroupBase.cs @@ -16,21 +16,17 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; -using System.Windows.Data; -using System.Diagnostics; -using System.Collections.Specialized; using System.Collections.ObjectModel; +using System.Collections.Specialized; using System.ComponentModel; +using System.Diagnostics; +using System.Windows; +using System.Windows.Data; namespace Xceed.Wpf.DataGrid { internal abstract class DataGridVirtualizingCollectionViewGroupBase : CollectionViewGroup, IWeakEventListener, IDisposable { - #region CONSTRUCTORS - internal DataGridVirtualizingCollectionViewGroupBase( object name, int initialItemsCount, @@ -47,25 +43,7 @@ namespace Xceed.Wpf.DataGrid m_startGlobalIndex = startGlobalIndex; } - #endregion CONSTRUCTORS - - - #region DO NOT USE THOSE - - #region Items PROPERTY - - [Obsolete( "The Items property is obsolete and has been replaced by the VirtualItems property. When referencing through a CollectionViewGroup, the CollectionViewGroupExtensions.GetItems extension method can be used.", true )] - public new ReadOnlyObservableCollection Items - { - get - { - return base.Items; - } - } - - #endregion Items PROPERTY - - #region ItemCount PROPERTY + #region ItemCount (Obselete) Property [Obsolete( "The ItemCount property is obsolete and has been replaced by the VirtualItemCount property. When referencing through a CollectionViewGroup, the CollectionViewGroupExtensions.GetItemCount extension method can be used.", true )] public new int ItemCount @@ -76,25 +54,22 @@ namespace Xceed.Wpf.DataGrid } } - #endregion ItemCount PROPERTY - - #endregion DO NOT USE THOSE - + #endregion - #region IsBottomLevel PROPERTY + #region Items (Obselete) Property - public override bool IsBottomLevel + [Obsolete( "The Items property is obsolete and has been replaced by the VirtualItems property. When referencing through a CollectionViewGroup, the CollectionViewGroupExtensions.GetItems extension method can be used.", true )] + public new ReadOnlyObservableCollection Items { get { - return m_isBottomLevel; + return base.Items; } } - #endregion IsBottomLevel PROPERTY - + #endregion - #region DATA VIRTUALIZATION + #region VirtualItemCount Property public int VirtualItemCount { @@ -120,7 +95,9 @@ namespace Xceed.Wpf.DataGrid } } - internal abstract int QueryItemCount(); + #endregion + + #region VirtualItems Property public IList VirtualItems { @@ -130,14 +107,12 @@ namespace Xceed.Wpf.DataGrid { this.EnsureProtectedVirtualItems(); + ObservableCollection observableProtectedItems = m_protectedVirtualItems as ObservableCollection; - ObservableCollection obserableProtectedItems = - m_protectedVirtualItems as ObservableCollection; - - if( obserableProtectedItems != null ) + if( observableProtectedItems != null ) { Debug.Assert( !m_isBottomLevel ); - m_virtualItems = new ReadOnlyObservableCollection( obserableProtectedItems ); + m_virtualItems = new ReadOnlyObservableCollection( observableProtectedItems ); } else { @@ -150,80 +125,68 @@ namespace Xceed.Wpf.DataGrid } } - private void EnsureProtectedVirtualItems() - { - if( m_protectedVirtualItems != null ) - return; - - DataGridVirtualizingCollectionViewBase collectionView = this.GetCollectionView(); + #endregion - Debug.Assert( collectionView != null ); + #region IsBottomLevel Property - if( m_isBottomLevel ) + public override bool IsBottomLevel + { + get { - m_protectedVirtualItems = this.CreateNewVirtualList(); + return m_isBottomLevel; } - else - { - ObservableCollection groupDescriptions = collectionView.GroupDescriptions; - - int groupDescriptionCount = ( groupDescriptions == null ) ? 0 : groupDescriptions.Count; - - int nextLevel = m_level + 1; - - if( nextLevel > ( groupDescriptionCount - 1 ) ) - throw new DataGridInternalException( "At attempt was made to retrieve child groups for a non-existing group description." ); - - GroupDescription subGroupBy = groupDescriptions[ nextLevel ]; + } - if( subGroupBy == null ) - throw new InvalidOperationException( "TODDOOC: " ); + #endregion - bool nextLevelIsBottom = ( nextLevel == ( groupDescriptionCount - 1 ) ); + #region Parent Property - m_protectedVirtualItems = this.QuerySubCollectionViewGroupList( subGroupBy, nextLevel, nextLevelIsBottom ); + internal DataGridVirtualizingCollectionViewGroupBase Parent + { + get + { + return m_parent; } } - private VirtualList CreateNewVirtualList() - { - Debug.Assert( m_isBottomLevel ); - - DataGridVirtualizingCollectionViewBase collectionView = this.GetCollectionView(); - - DataGridPageManagerBase virtualPageManagerBase = collectionView.RootGroup.GetVirtualPageManager(); + #endregion - VirtualList virtualItemList = new VirtualList( virtualPageManagerBase, m_virtualItemCount ); - virtualPageManagerBase.LinkVirtualListAndCollectionViewGroup( virtualItemList, this ); + #region Level Property - return virtualItemList; + internal int Level + { + get + { + return m_level; + } } - internal abstract ObservableCollection QuerySubCollectionViewGroupList( GroupDescription subGroupBy, int nextLevel, bool nextLevelIsBottom ); + #endregion + #region StartGlobalIndex Property - private int GetSubLevelCount() + internal int StartGlobalIndex { - CollectionView collectionView = this.GetCollectionView(); - - ObservableCollection groupDescriptions = collectionView.GroupDescriptions; - - int groupDescriptionsCount = ( groupDescriptions == null ) ? 0 : groupDescriptions.Count; - - DataGridVirtualizingCollectionViewGroupBase parentCollectionViewGroup = this.Parent; - - int level = 0; - while( parentCollectionViewGroup != null ) + get { - level++; - parentCollectionViewGroup = parentCollectionViewGroup.Parent; + return m_startGlobalIndex; } + } - Debug.Assert( groupDescriptionsCount >= level ); + #endregion - return ( groupDescriptionsCount - level ); + protected virtual DataGridVirtualizingCollectionViewBase GetCollectionView() + { + if( m_parent != null ) + return m_parent.GetCollectionView(); + + return null; } + internal abstract int QueryItemCount(); + + internal abstract ObservableCollection QuerySubCollectionViewGroupList( GroupDescription subGroupBy, int nextLevel, bool nextLevelIsBottom ); + internal virtual GroupDescription GetSubGroupBy() { CollectionView collectionView = this.GetCollectionView(); @@ -235,7 +198,6 @@ namespace Xceed.Wpf.DataGrid if( groupDescriptionsCount == 0 ) return null; - DataGridVirtualizingCollectionViewGroupBase parentCollectionViewGroup = this.Parent; int level = 0; @@ -254,87 +216,26 @@ namespace Xceed.Wpf.DataGrid { } - #endregion DATA VIRTUALIZATION - - - #region PROTECTED METHODS - - protected virtual DataGridVirtualizingCollectionViewBase GetCollectionView() - { - if( m_parent != null ) - return m_parent.GetCollectionView(); - - return null; - } - - #endregion PROTECTED METHODS - - #region INTERNAL PROPERTIES - - internal DataGridVirtualizingCollectionViewGroupBase Parent - { - get - { - return m_parent; - } - } - - internal int Level + internal virtual void DisposeCore() { - get - { - return m_level; - } + m_protectedVirtualItems = new List(); + m_virtualItems = m_protectedVirtualItems; + m_parent = null; } - internal int StartGlobalIndex + internal virtual int GetGlobalIndexOf( object item ) { - get - { - return m_startGlobalIndex; - } + return m_parent.GetGlobalIndexOf( item ); } - #endregion INTERNAL PROPERTIES - - #region INTERNAL METHODS - - private object OperateOnGlobalIndex( int index, Func function ) + internal virtual DataGridPageManagerBase GetVirtualPageManager() { - this.EnsureProtectedVirtualItems(); - - if( this.IsBottomLevel ) - { - return function( index, this ); - } - else - { - // The Count property of the virtualItems collection will return the sub-group count since this is not the bottom level. - int count = m_protectedVirtualItems.Count; - - for( int i = 0; i < count; i++ ) - { - DataGridVirtualizingCollectionViewGroupBase subGroup = m_protectedVirtualItems[ i ] as DataGridVirtualizingCollectionViewGroupBase; - - if( subGroup == null ) - throw new InvalidOperationException( "Sub-group cannot be null (Nothing in Visual Basic)." ); - - // VirtualItemCount will return the sum of data items contained in this group and its possible subgroups. - int subGroupItemCount = subGroup.VirtualItemCount; - - if( index < subGroupItemCount ) - return subGroup.OperateOnGlobalIndex( index, function ); - - index -= subGroupItemCount; - } - } - - throw new ArgumentOutOfRangeException( "index" ); + return m_parent.GetVirtualPageManager(); } internal object GetItemAtGlobalIndex( int globalIndex ) { - Func getItemFunction = ( localIndex, cvg ) => + Func getItemFunction = ( localIndex, cvg ) => { return cvg.m_protectedVirtualItems[ localIndex ]; }; @@ -344,7 +245,7 @@ namespace Xceed.Wpf.DataGrid internal void LockGlobalIndex( int globalIndex ) { - Func lockingAction = ( localIndex, cvg ) => + Func lockingAction = ( localIndex, cvg ) => { VirtualList virtualItemList = cvg.VirtualItems as VirtualList; @@ -367,16 +268,12 @@ namespace Xceed.Wpf.DataGrid { var rootGroup = collectionView.RootGroup; - if( ( rootGroup != null ) - && ( ( globalIndex >= rootGroup.m_virtualItemCount ) ) ) - { - // This can happen when refreshing a CollectionView and the record count has changed in such a way that the global index - // to unlock is out of range of the new count. + // This can happen when refreshing a CollectionView and the record count has changed in such a way that the global index to unlock is out of range of the new count. + if( ( rootGroup != null ) && ( ( globalIndex >= rootGroup.m_virtualItemCount ) ) ) return; - } } - Func unlockingAction = ( localIndex, cvg ) => + Func unlockingAction = ( localIndex, cvg ) => { VirtualList virtualItemList = cvg.VirtualItems as VirtualList; @@ -391,44 +288,111 @@ namespace Xceed.Wpf.DataGrid this.OperateOnGlobalIndex( globalIndex, unlockingAction ); } - internal virtual void DisposeCore() + private void EnsureProtectedVirtualItems() { - m_protectedVirtualItems = new List(); - m_virtualItems = m_protectedVirtualItems; - m_parent = null; + if( m_protectedVirtualItems != null ) + return; + + DataGridVirtualizingCollectionViewBase collectionView = this.GetCollectionView(); + + Debug.Assert( collectionView != null ); + + if( m_isBottomLevel ) + { + m_protectedVirtualItems = this.CreateNewVirtualList(); + } + else + { + ObservableCollection groupDescriptions = collectionView.GroupDescriptions; + + int groupDescriptionCount = ( groupDescriptions == null ) ? 0 : groupDescriptions.Count; + + int nextLevel = m_level + 1; + + if( nextLevel > ( groupDescriptionCount - 1 ) ) + throw new DataGridInternalException( "At attempt was made to retrieve child groups for a non-existing group description." ); + + GroupDescription subGroupBy = groupDescriptions[ nextLevel ]; + + if( subGroupBy == null ) + throw new InvalidOperationException( "TODDOOC: " ); + + bool nextLevelIsBottom = ( nextLevel == ( groupDescriptionCount - 1 ) ); + + m_protectedVirtualItems = this.QuerySubCollectionViewGroupList( subGroupBy, nextLevel, nextLevelIsBottom ); + } } - internal virtual int GetGlobalIndexOf( object item ) + private VirtualList CreateNewVirtualList() { - return m_parent.GetGlobalIndexOf( item ); + Debug.Assert( m_isBottomLevel ); + + DataGridVirtualizingCollectionViewBase collectionView = this.GetCollectionView(); + + DataGridPageManagerBase virtualPageManagerBase = collectionView.RootGroup.GetVirtualPageManager(); + + VirtualList virtualItemList = new VirtualList( virtualPageManagerBase, m_virtualItemCount ); + virtualPageManagerBase.LinkVirtualListAndCollectionViewGroup( virtualItemList, this ); + + return virtualItemList; } - internal virtual DataGridPageManagerBase GetVirtualPageManager() + private int GetSubLevelCount() { - return m_parent.GetVirtualPageManager(); - } + CollectionView collectionView = this.GetCollectionView(); - #endregion INTERNAL METHODS + ObservableCollection groupDescriptions = collectionView.GroupDescriptions; - #region PRIVATE FIELDS + int groupDescriptionsCount = ( groupDescriptions == null ) ? 0 : groupDescriptions.Count; - private bool m_isBottomLevel; - private int m_level; + DataGridVirtualizingCollectionViewGroupBase parentCollectionViewGroup = this.Parent; - private int m_startGlobalIndex; - private int m_virtualItemCount; + int level = 0; + while( parentCollectionViewGroup != null ) + { + level++; + parentCollectionViewGroup = parentCollectionViewGroup.Parent; + } - private IList m_protectedVirtualItems; - private IList m_virtualItems; + Debug.Assert( groupDescriptionsCount >= level ); - private DataGridVirtualizingCollectionViewGroupBase m_parent; + return ( groupDescriptionsCount - level ); + } + + private object OperateOnGlobalIndex( int index, Func function ) + { + this.EnsureProtectedVirtualItems(); + + if( this.IsBottomLevel ) + { + return function( index, this ); + } + else + { + // The Count property of the virtualItems collection will return the sub-group count since this is not the bottom level. + int count = m_protectedVirtualItems.Count; + + for( int i = 0; i < count; i++ ) + { + DataGridVirtualizingCollectionViewGroupBase subGroup = m_protectedVirtualItems[ i ] as DataGridVirtualizingCollectionViewGroupBase; + + if( subGroup == null ) + throw new InvalidOperationException( "Sub-group cannot be null (Nothing in Visual Basic)." ); - #endregion PRIVATE FIELDS + // VirtualItemCount will return the sum of data items contained in this group and its possible subgroups. + int subGroupItemCount = subGroup.VirtualItemCount; + + if( index < subGroupItemCount ) + return subGroup.OperateOnGlobalIndex( index, function ); + index -= subGroupItemCount; + } + } - #region WEAK EVENT HANDLER + throw new ArgumentOutOfRangeException( "index" ); + } - private void VirtualItemList_CollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) + private void OnVirtualItemListCollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) { DataGridVirtualizingCollectionViewBase collectionView = this.GetCollectionView(); @@ -440,21 +404,14 @@ namespace Xceed.Wpf.DataGrid { case NotifyCollectionChangedAction.Replace: { - deferredOperation = new DeferredOperation( - DeferredOperation.DeferredOperationAction.Replace, -1, - e.NewStartingIndex + m_startGlobalIndex, - e.NewItems, - e.OldStartingIndex + m_startGlobalIndex, - e.OldItems ); - + deferredOperation = new DeferredOperation( DeferredOperation.DeferredOperationAction.Replace, -1, e.NewStartingIndex + m_startGlobalIndex, + e.NewItems, e.OldStartingIndex + m_startGlobalIndex, e.OldItems ); break; } case NotifyCollectionChangedAction.Reset: { - deferredOperation = new DeferredOperation( - DeferredOperation.DeferredOperationAction.Refresh, -1, null ); - + deferredOperation = new DeferredOperation( DeferredOperation.DeferredOperationAction.Refresh, -1, null ); break; } @@ -463,19 +420,24 @@ namespace Xceed.Wpf.DataGrid } if( deferredOperation != null ) + { collectionView.ExecuteOrQueueSourceItemOperation( deferredOperation ); + } } } - #endregion WEAK EVENT HANDLER - #region IWeakEventListener Members bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) + { + return this.OnReceiveWeakEvent( managerType, sender, e ); + } + + protected virtual bool OnReceiveWeakEvent( Type managerType, object sender, EventArgs e ) { if( managerType == typeof( CollectionChangedEventManager ) ) { - this.VirtualItemList_CollectionChanged( sender, ( NotifyCollectionChangedEventArgs )e ); + this.OnVirtualItemListCollectionChanged( sender, ( NotifyCollectionChangedEventArgs )e ); return true; } @@ -484,7 +446,6 @@ namespace Xceed.Wpf.DataGrid #endregion IWeakEventListener Members - #region IDisposable Members public void Dispose() @@ -493,5 +454,16 @@ namespace Xceed.Wpf.DataGrid } #endregion + + private bool m_isBottomLevel; + private int m_level; + + private int m_startGlobalIndex; + private int m_virtualItemCount; + + private IList m_protectedVirtualItems; + private IList m_virtualItems; + + private DataGridVirtualizingCollectionViewGroupBase m_parent; } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewGroupRoot.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewGroupRoot.cs index 1b5cbc84..23038be3 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewGroupRoot.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewGroupRoot.cs @@ -14,21 +14,10 @@ ***********************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Collections.Specialized; -using System.Diagnostics; -using System.Collections.ObjectModel; -using System.ComponentModel; - namespace Xceed.Wpf.DataGrid { internal class DataGridVirtualizingCollectionViewGroupRoot : DataGridVirtualizingCollectionViewGroup { - #region CONSTRUCTORS - internal DataGridVirtualizingCollectionViewGroupRoot( DataGridVirtualizingCollectionView collectionView, bool isBottomLevel ) : base( null, -1, 0, null, -1, isBottomLevel ) { @@ -36,9 +25,10 @@ namespace Xceed.Wpf.DataGrid m_virtualPageManager = new DataGridPageManager( collectionView ); } - #endregion CONSTRUCTORS - - #region INTERNAL METHODS + protected override DataGridVirtualizingCollectionViewBase GetCollectionView() + { + return m_parentCollectionView; + } internal override int GetGlobalIndexOf( object item ) { @@ -57,23 +47,8 @@ namespace Xceed.Wpf.DataGrid base.DisposeCore(); } - #endregion - - #region PROTECTED METHODS - - protected override DataGridVirtualizingCollectionViewBase GetCollectionView() - { - return m_parentCollectionView; - } - - #endregion PROTECTED METHODS - - #region PRIVATE FILEDS - private DataGridVirtualizingCollectionView m_parentCollectionView; private DataGridPageManager m_virtualPageManager; - - #endregion PRIVATE FIELDS } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewSource.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewSource.cs index de68918e..52a9e952 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewSource.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewSource.cs @@ -75,14 +75,6 @@ namespace Xceed.Wpf.DataGrid this.QueryItems( this, e ); } - internal event EventHandler QueryAutoFilterDistinctValues; - - internal void OnQueryAutoFilterDistinctValues( QueryAutoFilterDistinctValuesEventArgs e ) - { - if( this.QueryAutoFilterDistinctValues != null ) - this.QueryAutoFilterDistinctValues( this, e ); - } - #endregion DATA VIRTUALIZATION EVENTS diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewSourceBase.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewSourceBase.cs index 152a0a94..eba1b266 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewSourceBase.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingCollectionViewSourceBase.cs @@ -15,12 +15,7 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Data; using System.Windows; -using System.Globalization; namespace Xceed.Wpf.DataGrid { @@ -80,7 +75,6 @@ namespace Xceed.Wpf.DataGrid #endregion MaxRealizedItemCount - #region PreemptivePageQueryRatio public static readonly DependencyProperty PreemptivePageQueryRatioProperty = DependencyProperty.Register( @@ -90,8 +84,14 @@ namespace Xceed.Wpf.DataGrid public double PreemptivePageQueryRatio { - get { return ( double )GetValue( DataGridVirtualizingCollectionViewSourceBase.PreemptivePageQueryRatioProperty ); } - set { this.SetValue( DataGridVirtualizingCollectionViewSourceBase.PreemptivePageQueryRatioProperty, value ); } + get + { + return ( double )GetValue( DataGridVirtualizingCollectionViewSourceBase.PreemptivePageQueryRatioProperty ); + } + set + { + this.SetValue( DataGridVirtualizingCollectionViewSourceBase.PreemptivePageQueryRatioProperty, value ); + } } #endregion PreemptivePageQueryRatio @@ -105,8 +105,14 @@ namespace Xceed.Wpf.DataGrid public CommitMode CommitMode { - get { return ( CommitMode )GetValue( DataGridVirtualizingCollectionViewSourceBase.CommitModeProperty ); } - set { this.SetValue( DataGridVirtualizingCollectionViewSourceBase.CommitModeProperty, value ); } + get + { + return ( CommitMode )GetValue( DataGridVirtualizingCollectionViewSourceBase.CommitModeProperty ); + } + set + { + this.SetValue( DataGridVirtualizingCollectionViewSourceBase.CommitModeProperty, value ); + } } #endregion CommitMode @@ -123,7 +129,6 @@ namespace Xceed.Wpf.DataGrid #endregion DATA VIRTUALIZATION EVENTS - #region INTERNAL PROPERTIES internal bool IsInitialized @@ -136,7 +141,6 @@ namespace Xceed.Wpf.DataGrid #endregion INTERNAL PROPERTIES - #region INTERNAL METHODS internal override void ApplyExtraPropertiesToView( DataGridCollectionViewBase currentView ) @@ -151,12 +155,10 @@ namespace Xceed.Wpf.DataGrid #endregion INTERNAL METHODS - #region PRIVATE FIELDS private bool m_isInitialized; #endregion PRIVATE FIELDS - } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingQueryableCollectionView.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingQueryableCollectionView.cs index 138a2ab4..9f9f979c 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingQueryableCollectionView.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingQueryableCollectionView.cs @@ -14,21 +14,16 @@ ***********************************************************************************/ -using System; +using System.Collections; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Data; using System.Diagnostics; -using System.Collections; +using System.Linq; using Xceed.Utils.Collections; namespace Xceed.Wpf.DataGrid { public sealed class DataGridVirtualizingQueryableCollectionView : DataGridVirtualizingCollectionViewBase { - #region CONSTRUCTORS - public DataGridVirtualizingQueryableCollectionView() : this( null, true, DataGridVirtualizingCollectionViewBase.DefaultPageSize, DataGridVirtualizingCollectionViewBase.DefaultMaxRealizedItemCount ) { @@ -45,8 +40,6 @@ namespace Xceed.Wpf.DataGrid m_pageManagerSyncRoot = new object(); } - #endregion CONSTRUCTORS - #region QueryableSource PROPERTY public IQueryable QueryableSource @@ -59,7 +52,6 @@ namespace Xceed.Wpf.DataGrid #endregion QueryableSource PROPERTY - #region INTERNAL METHODS internal override DataGridVirtualizingCollectionViewGroupBase CreateNewRootGroup() @@ -74,51 +66,6 @@ namespace Xceed.Wpf.DataGrid return ( ( DataGridVirtualizingQueryableCollectionViewGroupRoot )this.RootGroup ).GetVirtualPageManager().GetEnumerator(); } - internal override void RefreshDistinctValuesForField( DataGridItemPropertyBase dataGridItemProperty ) - { - if( dataGridItemProperty == null ) - return; - - if( dataGridItemProperty.CalculateDistinctValues == false ) - return; - - // List containing current column distinct values - HashSet currentColumnDistinctValues = new HashSet(); - - ReadOnlyObservableHashList readOnlyColumnDistinctValues = null; - - // If the key is not set in DistinctValues yet, do not calculate distinct values for this field - if( !( ( DistinctValuesDictionary )this.DistinctValues ).InternalTryGetValue( dataGridItemProperty.Name, out readOnlyColumnDistinctValues ) ) - return; - - ObservableHashList columnDistinctValues = readOnlyColumnDistinctValues.InnerObservableHashList; - - // We use the DistinctValuesSortComparer if present, else the SortComparer for the DataGridItemProperty, else, - // the Comparer used is the one of the base class. - IComparer distinctValuesSortComparer = dataGridItemProperty.DistinctValuesSortComparer; - - if( distinctValuesSortComparer == null ) - distinctValuesSortComparer = dataGridItemProperty.SortComparer; - - using( columnDistinctValues.DeferINotifyCollectionChanged() ) - { - DataGridVirtualizingQueryableCollectionViewGroupRoot rootGroup = this.RootGroup as DataGridVirtualizingQueryableCollectionViewGroupRoot; - - Debug.Assert( rootGroup != null ); - - object[] distinctValues = rootGroup.GetItemPropertyDistinctValues( dataGridItemProperty ); - - foreach( object distinctValue in distinctValues ) - { - // Compute current value to be able to remove unused values - currentColumnDistinctValues.Add( distinctValue ); - } - - DataGridCollectionViewBase.RemoveUnusedDistinctValues( - distinctValuesSortComparer, currentColumnDistinctValues, columnDistinctValues, null ); - } - } - #endregion #region PRIVATE FIELDS diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingQueryableCollectionViewGroupRoot.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingQueryableCollectionViewGroupRoot.cs index 94061488..7b2d2522 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingQueryableCollectionViewGroupRoot.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingQueryableCollectionViewGroupRoot.cs @@ -22,7 +22,6 @@ using System.Diagnostics; using System.ComponentModel; using System.Collections; using System.Linq.Expressions; -using Xceed.Wpf.DataGrid.FilterCriteria; namespace Xceed.Wpf.DataGrid { @@ -78,165 +77,6 @@ namespace Xceed.Wpf.DataGrid #region INTERNAL METHODS - internal override IQueryable CreateUnsortedFilteredQueryable() - { - if( m_unsortedFilteredQueryableSource == null ) - { - if( m_queryableSource != null ) - { - ParameterExpression sharedParameterExpression = m_queryableSource.CreateParameterExpression(); - - Expression filterCriterionsExpression = this.GetFilterCriterionsExpression( m_queryableSource, sharedParameterExpression ); - Expression autoFilterValuesExpression = this.GetAutoFilterValuesExpression( m_queryableSource, sharedParameterExpression ); - - Expression completeFilterExpression = null; - - if( filterCriterionsExpression != null ) - completeFilterExpression = filterCriterionsExpression; - - if( autoFilterValuesExpression != null ) - { - if( completeFilterExpression == null ) - { - completeFilterExpression = autoFilterValuesExpression; - } - else - { - completeFilterExpression = Expression.And( completeFilterExpression, autoFilterValuesExpression ); - } - } - - // Apply the complete filter expression, or if null, set the root source. - if( completeFilterExpression == null ) - { - m_unsortedFilteredQueryableSource = m_queryableSource; - } - else - { - m_unsortedFilteredQueryableSource = m_queryableSource.WhereFilter( sharedParameterExpression, completeFilterExpression ); - } - } - } - - return m_unsortedFilteredQueryableSource; - } - - private Expression GetFilterCriterionsExpression( IQueryable queryable, ParameterExpression sharedParameterExpression ) - { - if( queryable == null ) - throw new ArgumentNullException( "queryable" ); - - FilterCriteriaMode filterCriteriaMode = m_parentCollectionView.FilterCriteriaMode; - - if( filterCriteriaMode == FilterCriteriaMode.None ) - return null; - - - DataGridItemPropertyCollection itemProperties = m_parentCollectionView.ItemProperties; - int itemPropertiesCount = itemProperties.Count; - - Expression filterCriterionsExpression = null; - - for( int i = 0; i < itemPropertiesCount; i++ ) - { - DataGridItemPropertyBase itemProperty = itemProperties[ i ]; - string itemPropertyName = itemProperty.Name; - - FilterCriterion filterCriterion = itemProperty.FilterCriterion; - - if( filterCriterion == null ) - continue; - - Expression propertyFilterCriterionExpression = filterCriterion.ToLinqExpression( queryable, sharedParameterExpression, itemPropertyName ); - - if( propertyFilterCriterionExpression == null ) - continue; - - if( filterCriterionsExpression == null ) - { - filterCriterionsExpression = propertyFilterCriterionExpression; - } - else - { - Debug.Assert( ( filterCriteriaMode == FilterCriteriaMode.And ) || ( filterCriteriaMode == FilterCriteriaMode.Or ) ); - - // Merge this DataGridItemProperty FilterCriterionExpressions - if( filterCriteriaMode == FilterCriteriaMode.And ) - { - filterCriterionsExpression = Expression.And( filterCriterionsExpression, propertyFilterCriterionExpression ); - } - else - { - filterCriterionsExpression = Expression.Or( filterCriterionsExpression, propertyFilterCriterionExpression ); - } - } - - // Loop to next DataGridItemProperty. - } - - return filterCriterionsExpression; - } - - private Expression GetAutoFilterValuesExpression( IQueryable queryable, ParameterExpression sharedParameterExpression ) - { - if( queryable == null ) - throw new ArgumentNullException( "queryable" ); - - AutoFilterMode autoFilterMode = m_parentCollectionView.AutoFilterMode; - - if( autoFilterMode == AutoFilterMode.None ) - return null; - - DataGridItemPropertyCollection itemProperties = m_parentCollectionView.ItemProperties; - int itemPropertiesCount = itemProperties.Count; - - Expression autoFilterValuesExpression = null; - - for( int i = 0; i < itemPropertiesCount; i++ ) - { - DataGridItemPropertyBase itemProperty = itemProperties[ i ]; - string itemPropertyName = itemProperty.Name; - - IList itemPropertyAutoFilterValues; - - if( m_parentCollectionView.AutoFilterValues.TryGetValue( itemPropertyName, out itemPropertyAutoFilterValues ) ) - { - int itemPropertyAutoFilterValuesCount = itemPropertyAutoFilterValues.Count; - - if( itemPropertyAutoFilterValuesCount == 0 ) - continue; - - - object[] itemPropertyAutoFilterValuesArray = new object[ itemPropertyAutoFilterValuesCount ]; - itemPropertyAutoFilterValues.CopyTo( itemPropertyAutoFilterValuesArray, 0 ); - - Expression itemPropertyAutoFilterExpression = queryable.CreateEqualExpression( sharedParameterExpression, itemPropertyName, itemPropertyAutoFilterValuesArray ); - - if( autoFilterValuesExpression == null ) - { - autoFilterValuesExpression = itemPropertyAutoFilterExpression; - } - else - { - Debug.Assert( ( autoFilterMode == AutoFilterMode.And ) || ( autoFilterMode == AutoFilterMode.Or ) ); - - // Merge this DataGridItemProperty AutoFilterExpressions - if( autoFilterMode == AutoFilterMode.And ) - { - autoFilterValuesExpression = Expression.And( autoFilterValuesExpression, itemPropertyAutoFilterExpression ); - } - else - { - autoFilterValuesExpression = Expression.Or( autoFilterValuesExpression, itemPropertyAutoFilterExpression ); - } - } - } - // Loop to next DataGridItemProperty. - } - - return autoFilterValuesExpression; - } - internal override int GetGlobalIndexOf( object item ) { return m_virtualPageManager.GetGlobalIndexOf( item ); @@ -280,7 +120,6 @@ namespace Xceed.Wpf.DataGrid { m_parentCollectionView = null; m_queryableSource = null; - m_unsortedFilteredQueryableSource = null; m_virtualPageManager = null; base.DisposeCore(); } @@ -292,7 +131,6 @@ namespace Xceed.Wpf.DataGrid private DataGridVirtualizingQueryableCollectionView m_parentCollectionView; private IQueryable m_queryableSource; - private IQueryable m_unsortedFilteredQueryableSource; private string[] m_primaryKeyPropertyNames; diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingQueryableCollectionViewSource.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingQueryableCollectionViewSource.cs index 8f394774..42fb6592 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingQueryableCollectionViewSource.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridVirtualizingQueryableCollectionViewSource.cs @@ -14,19 +14,15 @@ ***********************************************************************************/ -using System; -using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Windows.Data; using System.Windows; +using System.Windows.Data; +using System.Windows.Threading; namespace Xceed.Wpf.DataGrid { public class DataGridVirtualizingQueryableCollectionViewSource : DataGridVirtualizingCollectionViewSourceBase { - #region CONSTRUCTORS - static DataGridVirtualizingQueryableCollectionViewSource() { CollectionViewSource.CollectionViewTypeProperty.OverrideMetadata( @@ -34,49 +30,48 @@ namespace Xceed.Wpf.DataGrid new FrameworkPropertyMetadata( typeof( DataGridVirtualizingQueryableCollectionView ) ) ); } - public DataGridVirtualizingQueryableCollectionViewSource() - : base() - { - } - - #endregion CONSTRUCTORS - - #region QueryableSource + #region QueryableSource Property public static readonly DependencyProperty QueryableSourceProperty = DependencyProperty.Register( - "QueryableSource", typeof( IQueryable ), typeof( DataGridVirtualizingQueryableCollectionViewSource ), + "QueryableSource", + typeof( IQueryable ), + typeof( DataGridVirtualizingQueryableCollectionViewSource ), new FrameworkPropertyMetadata( null, new PropertyChangedCallback( DataGridVirtualizingQueryableCollectionViewSource.OnQueryableSourcePropertyChanged ) ) ); public IQueryable QueryableSource { - get { return ( IQueryable )GetValue( DataGridVirtualizingQueryableCollectionViewSource.QueryableSourceProperty ); } - set { this.SetValue( DataGridVirtualizingQueryableCollectionViewSource.QueryableSourceProperty, value ); } + get + { + return ( IQueryable )GetValue( DataGridVirtualizingQueryableCollectionViewSource.QueryableSourceProperty ); + } + set + { + this.SetValue( DataGridVirtualizingQueryableCollectionViewSource.QueryableSourceProperty, value ); + } } private static void OnQueryableSourcePropertyChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - DataGridCollectionViewSourceBase source = sender as DataGridCollectionViewSourceBase; - + var source = sender as DataGridCollectionViewSourceBase; if( source == null ) return; source.AdviseForwardedPropertyChanged(); - if( source.DataSourceProvider != null ) - source.DataSourceProvider.DelayRefresh( source.Dispatcher, System.Windows.Threading.DispatcherPriority.DataBind ); + var provider = source.DataSourceProvider; + if( provider != null ) + { + provider.DelayRefresh( source.Dispatcher, DispatcherPriority.DataBind ); + } } - #endregion QueryableSource - - #region OVERRIDES + #endregion internal override DataGridCollectionViewBaseDataProvider CreateDataProvider() { return new DataGridVirtualizingQueryableCollectionViewDataProvider( this ); } - - #endregion OVERRIDES } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataRelationDetailDescription.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataRelationDetailDescription.cs index 3c7c19e9..5fc2db7b 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataRelationDetailDescription.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataRelationDetailDescription.cs @@ -15,11 +15,8 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Text; -using System.Data; -using System.Diagnostics; using System.Collections; +using System.Data; namespace Xceed.Wpf.DataGrid { @@ -40,6 +37,8 @@ namespace Xceed.Wpf.DataGrid m_userAssignedDataRelation = true; } + #region DataRelation Property + [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly" )] public DataRelation DataRelation { @@ -61,6 +60,8 @@ namespace Xceed.Wpf.DataGrid } } + #endregion + protected internal override void Initialize( DataGridCollectionViewBase parentCollectionView ) { base.Initialize( parentCollectionView ); diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataRowColumnPropertyDescriptor.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataRowColumnPropertyDescriptor.cs index 23926f64..2abf397e 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataRowColumnPropertyDescriptor.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataRowColumnPropertyDescriptor.cs @@ -15,44 +15,44 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Text; +using System.Collections; using System.ComponentModel; using System.Data; -using System.Collections; namespace Xceed.Wpf.DataGrid { - internal class DataRowColumnPropertyDescriptor : PropertyDescriptor + internal sealed class DataRowColumnPropertyDescriptor : PropertyDescriptor { - public DataRowColumnPropertyDescriptor( System.Data.DataColumn column ) + internal DataRowColumnPropertyDescriptor( DataColumn column ) : base( column.ColumnName, null ) { if( column == null ) throw new ArgumentNullException( "column" ); - m_columnName = column.ColumnName; - m_columnDataType = ItemsSourceHelper.GetColumnDataType( column ); - m_columnCaption = column.Caption; - m_columnReadOnly = column.ReadOnly; - m_columnHidden = ( column.ColumnMapping == MappingType.Hidden ); + m_column = column; } + #region DisplayName Property + public override string DisplayName { get { - return m_columnCaption; + return m_column.Caption; } } + #endregion + + #region Attributes Property + public override AttributeCollection Attributes { get { if( typeof( IList ).IsAssignableFrom( this.PropertyType ) ) { - Attribute[] array = new Attribute[ base.Attributes.Count + 1 ]; + var array = new Attribute[ base.Attributes.Count + 1 ]; base.Attributes.CopyTo( array, 0 ); array[ array.Length - 1 ] = new ListBindableAttribute( false ); return new AttributeCollection( array ); @@ -62,6 +62,10 @@ namespace Xceed.Wpf.DataGrid } } + #endregion + + #region ComponentType Property + public override Type ComponentType { get @@ -70,51 +74,64 @@ namespace Xceed.Wpf.DataGrid } } + #endregion + + #region IsBrowsable Property + public override bool IsBrowsable { get { - if( m_columnHidden ) - return false; - - return base.IsBrowsable; + return ( m_column.ColumnMapping != MappingType.Hidden ) + && ( base.IsBrowsable ); } } + #endregion + + #region IsReadOnly Property + public override bool IsReadOnly { get { - return m_columnReadOnly; + return m_column.ReadOnly; } } + #endregion + + #region PropertyType Property + public override Type PropertyType { get { - return m_columnDataType; + return ItemsSourceHelper.GetColumnDataType( m_column ); } } + #endregion + public override bool CanResetValue( object component ) { - object value = this.GetValue( component ); - return ( value != null ) && ( value != DBNull.Value ); + var value = this.GetValue( component ); + + return ( value != null ) + && ( value != DBNull.Value ); } public override object GetValue( object component ) { - System.Data.DataRow dataRow = component as System.Data.DataRow; - + var dataRow = component as System.Data.DataRow; if( dataRow == null ) return null; - object value = null; + var value = default( object ); try { - value = dataRow[ m_columnName ]; + value = dataRow[ m_column ]; } catch { @@ -133,15 +150,14 @@ namespace Xceed.Wpf.DataGrid public override void SetValue( object component, object value ) { - System.Data.DataRow dataRow = component as System.Data.DataRow; - + var dataRow = component as System.Data.DataRow; if( dataRow == null ) throw new InvalidOperationException( "An attempt was made to set a value on a DataRow that does not exist." ); if( this.IsReadOnly ) throw new InvalidOperationException( "An attempt was made to set a value on a read-only field." ); - object oldValue = dataRow[ m_columnName ]; + var oldValue = dataRow[ m_column ]; if( ( oldValue == null ) || ( oldValue == DBNull.Value ) ) { @@ -156,11 +172,11 @@ namespace Xceed.Wpf.DataGrid if( value == null ) { - dataRow[ m_columnName ] = DBNull.Value; + dataRow[ m_column ] = DBNull.Value; } else { - dataRow[ m_columnName ] = value; + dataRow[ m_column ] = value; } this.OnValueChanged( component, EventArgs.Empty ); @@ -171,10 +187,6 @@ namespace Xceed.Wpf.DataGrid return false; } - private string m_columnName; - private Type m_columnDataType; - private string m_columnCaption; - private bool m_columnReadOnly; - private bool m_columnHidden; + private readonly DataColumn m_column; } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DeferredOperationManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DeferredOperationManager.cs index 5acc863e..4db22b8b 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DeferredOperationManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DeferredOperationManager.cs @@ -53,7 +53,7 @@ namespace Xceed.Wpf.DataGrid { lock( this ) { - return ( m_pendingFlags.Data != 0 ) || ( !m_isProcessingOperations && m_deferredOperations.Count > 0 ); + return ( m_pendingFlags.Data != 0 ) || ( m_deferredOperations.Count > 0 ); } } } @@ -153,7 +153,7 @@ namespace Xceed.Wpf.DataGrid lock( this ) { //Make sure that stats calculation that have been defer are processed before defering again! - if( value && m_deferredOperationsToProcess > 0 ) + if( value && ( m_deferredOperationsToProcess > 0 ) ) { m_forceProcessOfInvalidatedGroupStats = true; } @@ -203,24 +203,24 @@ namespace Xceed.Wpf.DataGrid { if( m_deferredOperations.Count >= 2 ) { - DeferredOperation addOperation = m_deferredOperations[ 0 ]; + var addOperation = m_deferredOperations[ 0 ]; if( addOperation.Action != DeferredOperation.DeferredOperationAction.Add ) return; - int addIndex = addOperation.NewStartingIndex; - int addCount = addOperation.NewItems.Count; + var addIndex = addOperation.NewStartingIndex; + var addCount = addOperation.NewItems.Count; - int firstIndexToRemove = 1; - int lastIndexToRemove = -1; + var firstIndexToRemove = 1; + var lastIndexToRemove = -1; - int count = m_deferredOperations.Count; + var count = m_deferredOperations.Count; for( int i = 1; i < count; i++ ) { - DeferredOperation operation = m_deferredOperations[ i ]; + var operation = m_deferredOperations[ i ]; - bool replaced = ( operation.Action == DeferredOperation.DeferredOperationAction.Replace ); - bool removed = ( operation.Action == DeferredOperation.DeferredOperationAction.Remove ); + var replaced = ( operation.Action == DeferredOperation.DeferredOperationAction.Replace ); + var removed = ( operation.Action == DeferredOperation.DeferredOperationAction.Remove ); if( replaced || removed ) { @@ -230,8 +230,7 @@ namespace Xceed.Wpf.DataGrid return; } - if( ( addIndex == operation.OldStartingIndex ) - && ( addCount == operation.OldItems.Count ) ) + if( ( addIndex == operation.OldStartingIndex ) && ( addCount == operation.OldItems.Count ) ) { lastIndexToRemove = i; @@ -248,8 +247,7 @@ namespace Xceed.Wpf.DataGrid } else { - // Can be normal, we can receive 2 add for the same item and same position - // when we are bound to an IBindingList ( like a DataView ) + // Can be normal, we can receive 2 adds for the same item and same position when we are bound to an IBindingList ( like a DataView ) return; } } @@ -358,7 +356,7 @@ namespace Xceed.Wpf.DataGrid this.Process( true ); } - public void InvalidateGroupStats( DataGridCollectionViewGroup group, bool calculateAllStats = false ) + public void InvalidateGroupStats( DataGridCollectionViewGroup group, bool calculateAllStats = false, bool resortGroups = true ) { if( group == null ) return; @@ -368,8 +366,11 @@ namespace Xceed.Wpf.DataGrid if( this.RefreshPending ) return; - DataGridCollectionViewGroup parent = group; + // When set to false, this will prevent group resorting when the DataGridCollectionView.ProcessInvalidatedGroupStats() is called through the disptached call below. + // If the current method is called again and this variable is set to true before groups are processed, it will be fine, as the grid is now in a state that will support group resorting. + m_resortGroups = resortGroups; + var parent = group; while( parent != null ) { if( !m_invalidatedGroups.Contains( parent ) ) @@ -377,8 +378,6 @@ namespace Xceed.Wpf.DataGrid m_invalidatedGroups.Add( parent ); } - parent.ClearStatFunctionsResult(); - parent.CalculateAllStats = calculateAllStats; parent = parent.Parent; } @@ -397,37 +396,6 @@ namespace Xceed.Wpf.DataGrid } } - public bool ContainsItemForRemoveOperation( object item ) - { - if( item == null ) - throw new ArgumentNullException( "item" ); - - if( m_deferredOperations.Count == 0 ) - return false; - - int deferredOperationsCount = m_deferredOperations.Count; - - for( int i = 0; i < deferredOperationsCount; i++ ) - { - DeferredOperation deferredOperation = m_deferredOperations[ i ]; - - if( deferredOperation.Action == DeferredOperation.DeferredOperationAction.Remove ) - { - int oldItemsCount = ( deferredOperation.OldItems == null ) ? 0 : deferredOperation.OldItems.Count; - - for( int j = 0; j < oldItemsCount; j++ ) - { - object oldItem = deferredOperation.OldItems[ j ]; - - if( object.Equals( oldItem, item ) ) - return true; - } - } - } - - return false; - } - private object Dispatched_Process( object e ) { this.Process( false ); @@ -472,9 +440,12 @@ namespace Xceed.Wpf.DataGrid m_hasNewOperationsSinceStartTime = false; } - // The fact of processing a deferredOperations can cause other DeferRefresh on the CollectionView that will finaly call this Process() again even if not yet completed. - // So we must cache all the flags in local variable to prevent double execution of the operation, except for m_deferredOperation which has its own flag is set. - m_isProcessingOperations = true; + // A deferredOperation can cause a DeferRefresh to be disposed of, hence provoking a re-entry in this method. + // As a result, all variables must be cached to prevent re-executing the same deferredOperation. + + List deferredOperations = m_deferredOperations; + //Set a new list in case new operations are added while processing the current operations. + m_deferredOperations = new List( 10 ); bool refreshDistincValuesWithFilteredItemChangedPending = this.RefreshDistincValuesWithFilteredItemChangedPending; this.RefreshDistincValuesWithFilteredItemChangedPending = false; bool refreshDistincValuesPending = this.RefreshDistincValuesPending; @@ -504,35 +475,48 @@ namespace Xceed.Wpf.DataGrid m_collectionView.ExecuteSourceItemOperation( new DeferredOperation( DeferredOperation.DeferredOperationAction.Resort, -1, null ), out refreshForced ); } - if( ( m_deferredOperations.Count > 0 ) && ( !refreshForced ) ) + if( ( deferredOperations.Count > 0 ) && ( !refreshForced ) ) { - int count = m_deferredOperations.Count; + int count = deferredOperations.Count; int operationIndex = 0; while( ( operationIndex < count ) && ( !refreshForced ) && ( processAll || ( DateTime.UtcNow.Subtract( startTime ) < DeferredOperationManager.MaxProcessDuration ) ) ) { - m_collectionView.ExecuteSourceItemOperation( m_deferredOperations[ operationIndex ], out refreshForced ); + m_collectionView.ExecuteSourceItemOperation( deferredOperations[ operationIndex ], out refreshForced ); operationIndex++; } if( ( operationIndex < count ) && ( !refreshForced ) ) { - m_deferredOperations.RemoveRange( 0, operationIndex ); + deferredOperations.RemoveRange( 0, operationIndex ); m_deferredOperationsToProcess -= operationIndex; } else { - m_deferredOperations.Clear(); + deferredOperations.Clear(); m_deferredOperationsToProcess = 0; } } - m_isProcessingOperations = false; + if( m_deferredOperations.Count == 0 ) + { + m_deferredOperations = deferredOperations; + } + else + { + // When this method is re-entered, the processAll parameter should be true, which means all deferredOperations should have been processed. When assigning it back to m_deferredOperations, + // it's count should be 0. Thus in the previous call on the stack, the "if" condition should always be true, hence this assert. + Debug.Assert( false, "Should never get there." ); + + //To be GC friendly, keep the original list, which at one point is the one created with a capacity of a 1000 items. + deferredOperations.InsertRange( deferredOperations.Count, m_deferredOperations ); + m_deferredOperations = deferredOperations; + } // The recalculation of the StatFunctions is performed last. if( ( m_deferredOperationsToProcess <= 0 || m_forceProcessOfInvalidatedGroupStats ) && ( m_invalidatedGroups.Count != 0 ) ) { - m_collectionView.ProcessInvalidatedGroupStats( m_invalidatedGroups ); + m_collectionView.ProcessInvalidatedGroupStats( m_invalidatedGroups, m_resortGroups ); m_invalidatedGroups.Clear(); m_forceProcessOfInvalidatedGroupStats = false; } @@ -594,8 +578,8 @@ namespace Xceed.Wpf.DataGrid private HashSet m_invalidatedGroups; private int m_deferredOperationsToProcess; private BitVector32 m_pendingFlags; - private bool m_isProcessingOperations; private bool m_forceProcessOfInvalidatedGroupStats; + private bool m_resortGroups; private readonly Dispatcher m_dispatcher; private DispatcherOperation m_dispatcherOperation; diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DistinctValuesDictionary.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DistinctValuesDictionary.cs index a71e2d08..000071d4 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DistinctValuesDictionary.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DistinctValuesDictionary.cs @@ -62,7 +62,6 @@ namespace Xceed.Wpf.DataGrid { value = new ReadOnlyObservableHashList(); this.InternalAdd( key, value ); - m_dataGridCollectionViewBase.ForceRefreshDistinctValuesForFieldName( key ); } Debug.Assert( value != null ); diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DistinctValuesRefreshNeededEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DistinctValuesRefreshNeededEventManager.cs index 983f7c35..f9423cce 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DistinctValuesRefreshNeededEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DistinctValuesRefreshNeededEventManager.cs @@ -74,14 +74,10 @@ namespace Xceed.Wpf.DataGrid protected override void StartListening( object source ) { - var target = ( DataGridCollectionViewBase )source; - target.DistinctValuesRefreshNeeded += new EventHandler( this.DeliverEvent ); } protected override void StopListening( object source ) { - var target = ( DataGridCollectionViewBase )source; - target.DistinctValuesRefreshNeeded -= new EventHandler( this.DeliverEvent ); } } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/EntityDetailDescription.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/EntityDetailDescription.cs index 4515e31f..da4dc938 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/EntityDetailDescription.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/EntityDetailDescription.cs @@ -15,24 +15,16 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Collections; -using System.Data.Objects; +using System.ComponentModel; using System.Data.Objects.DataClasses; using System.Reflection; -using System.Windows; -using System.ComponentModel; namespace Xceed.Wpf.DataGrid { internal class EntityDetailDescription : DataGridDetailDescription { - #region CONSTRUCTORS - public EntityDetailDescription() - : base() { } @@ -45,21 +37,20 @@ namespace Xceed.Wpf.DataGrid this.RelationName = propertyName; } - #endregion CONSTRUCTORS - #region QueryDetails Event public event EventHandler QueryDetails; protected virtual void OnQueryDetails( QueryEntityDetailsEventArgs e ) { - if( this.QueryDetails != null ) - this.QueryDetails( this, e ); - } + var handler = this.QueryDetails; + if( handler == null ) + return; - #endregion QueryDetails Event + handler.Invoke( this, e ); + } - #region DataGridDetailDescription Overrides + #endregion protected internal override IEnumerable GetDetailsForParentItem( DataGridCollectionViewBase parentCollectionView, object parentItem ) { @@ -94,8 +85,8 @@ namespace Xceed.Wpf.DataGrid { // Make sure that the details are loaded // except if the user already handled it. - if( !relatedEnd.IsLoaded - && !args.Handled + if( !relatedEnd.IsLoaded + && !args.Handled && entityObjectLoadable ) { relatedEnd.Load(); @@ -112,7 +103,5 @@ namespace Xceed.Wpf.DataGrid return null; } - - #endregion DataGridDetailDescription Overrides } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/GroupSortComparer.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/GroupSortComparer.cs index 0232f6ed..4483ee7d 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/GroupSortComparer.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/GroupSortComparer.cs @@ -54,25 +54,22 @@ namespace Xceed.Wpf.DataGrid } } - ListSortDirection sortDirection = ListSortDirection.Ascending; + var sortDirection = ListSortDirection.Ascending; int result; foreach( SortInfo sortInfo in m_sortInfos ) - //for( int i = 0; i < sortInfoCount; i++ ) { - string statResultPropertyName = sortInfo.StatResultPropertyName; - IComparer sortComparer = sortInfo.SortComparer; + var foreignKeyDescription = sortInfo.ForeignKeyDescription; + var sortComparer = sortInfo.SortComparer; sortDirection = sortInfo.SortDirection; - if( statResultPropertyName == null ) + if( foreignKeyDescription != null ) { - result = sortComparer.Compare( xGroup.Name, yGroup.Name ); + result = sortComparer.Compare( foreignKeyDescription.GetDisplayValue( xGroup.Name ), foreignKeyDescription.GetDisplayValue( yGroup.Name ) ); } else { - result = sortComparer.Compare( - xGroup.GetStatFunctionValue( statResultPropertyName ), - yGroup.GetStatFunctionValue( statResultPropertyName ) ); + result = sortComparer.Compare( xGroup.Name, yGroup.Name ); } if( result != 0 ) @@ -96,33 +93,55 @@ namespace Xceed.Wpf.DataGrid public class SortInfo { - public SortInfo( string statResultPropertyName, ListSortDirection sortDirection, IComparer sortComparer ) + public SortInfo( ListSortDirection sortDirection, IComparer sortComparer ) { if( sortComparer == null ) throw new ArgumentNullException( "sortComparer" ); - this.StatResultPropertyName = statResultPropertyName; this.SortDirection = sortDirection; this.SortComparer = sortComparer; } - public string StatResultPropertyName + public SortInfo( DataGridForeignKeyDescription foreignKeyDescription, ListSortDirection sortDirection, IComparer sortComparer ) + { + if( sortComparer == null ) + throw new ArgumentNullException( "sortComparer" ); + + this.ForeignKeyDescription = foreignKeyDescription; + this.SortDirection = sortDirection; + this.SortComparer = sortComparer; + } + + + #region ForeignKeyDescription Property + + internal DataGridForeignKeyDescription ForeignKeyDescription { get; private set; } + #endregion + + #region SortDirection Property + public ListSortDirection SortDirection { get; private set; } + #endregion + + #region SortComparer Property + public IComparer SortComparer { get; private set; } + + #endregion } } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/PropertyDetailDescription.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/PropertyDetailDescription.cs index 11f4171c..3f6fd826 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/PropertyDetailDescription.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/PropertyDetailDescription.cs @@ -15,10 +15,8 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Text; -using System.ComponentModel; using System.Collections; +using System.ComponentModel; namespace Xceed.Wpf.DataGrid { @@ -38,6 +36,8 @@ namespace Xceed.Wpf.DataGrid this.PropertyDescriptor = relation; } + #region PropertyDescriptor Property + [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly" )] public PropertyDescriptor PropertyDescriptor { @@ -60,6 +60,10 @@ namespace Xceed.Wpf.DataGrid } } + private PropertyDescriptor m_propertyDescriptor; + + #endregion + protected internal override void Initialize( DataGridCollectionViewBase parentCollectionView ) { base.Initialize( parentCollectionView ); @@ -72,56 +76,31 @@ namespace Xceed.Wpf.DataGrid if( String.IsNullOrEmpty( relationName ) == true ) throw new InvalidOperationException( "An attempt was made to initialize a PropertyDetailDescription whose Name property has not been set." ); - foreach( DataGridDetailDescription detailDescription in parentCollectionView.DetailDescriptions.DefaultDetailDescriptions ) + var enumeration = parentCollectionView as IEnumerable; + if( enumeration != null ) { - PropertyDetailDescription propertyDetailDescription = detailDescription as PropertyDetailDescription; - if( propertyDetailDescription != null ) + // Try to get it from the first item in the DataGridCollectionView + var firstItem = ItemsSourceHelper.GetFirstItemByEnumerable( enumeration ); + if( firstItem != null ) { - if( propertyDetailDescription.RelationName == relationName ) + var propertyDescriptor = this.GetPropertyDescriptorFromFirstItem( firstItem ); + if( propertyDescriptor != null ) { - this.PropertyDescriptor = propertyDetailDescription.PropertyDescriptor; + this.PropertyDescriptor = propertyDescriptor; return; } } } - // The DetailDescription for RelationName was not found in DefaultDetailDescription - // and may not have the PropertyDetailDescriptionAttribute - if( this.PropertyDescriptor == null ) + // If the list is empty, check if the SourceCollection is ITypedList + var typedList = parentCollectionView.SourceCollection as ITypedList; + if( typedList != null ) { - PropertyDescriptor relationDescriptor = null; - - IEnumerable enumeration = parentCollectionView as IEnumerable; - - if( enumeration != null ) - { - // Try to get it from the first item in the DataGridCollectionView - object firstItem = ItemsSourceHelper.GetFirstItemByEnumerable( enumeration ); - - if( firstItem != null ) - { - relationDescriptor = this.GetPropertyDescriptorFromFirstItem( firstItem ); - - if( relationDescriptor != null ) - { - this.PropertyDescriptor = relationDescriptor; - return; - } - } - } - - // If the list is empty, check if the SourceCollection is ITypedList - ITypedList iTypedList = parentCollectionView.SourceCollection as ITypedList; - - if( iTypedList != null ) + var propertyDescriptor = this.GetPropertyDescriptorFromITypedList( typedList ); + if( propertyDescriptor != null ) { - relationDescriptor = this.GetPropertyDescriptorFromITypedList( iTypedList ); - - if( relationDescriptor != null ) - { - this.PropertyDescriptor = relationDescriptor; - return; - } + this.PropertyDescriptor = propertyDescriptor; + return; } } @@ -133,9 +112,7 @@ namespace Xceed.Wpf.DataGrid if( string.IsNullOrEmpty( this.RelationName ) || ( typedList == null ) ) return null; - PropertyDescriptorCollection properties; - - properties = typedList.GetItemProperties( null ); + var properties = typedList.GetItemProperties( null ); if( ( properties != null ) && ( properties.Count > 0 ) ) return properties[ this.RelationName ]; @@ -167,7 +144,7 @@ namespace Xceed.Wpf.DataGrid if( string.IsNullOrEmpty( this.RelationName ) || ( firstItem == null ) ) return null; - var descriptor = ItemsSourceHelper.GetCustomTypeDescriptor( firstItem, firstItem.GetType() ); + var descriptor = ItemsSourceHelper.GetCustomTypeDescriptorFromItem( firstItem, firstItem.GetType() ); if( descriptor == null ) return null; @@ -185,16 +162,14 @@ namespace Xceed.Wpf.DataGrid this.Seal(); - object value = this.PropertyDescriptor.GetValue( parentItem ); - + var value = this.PropertyDescriptor.GetValue( parentItem ); if( value == null ) return null; - IEnumerable enumeration = value as IEnumerable; - + var enumeration = value as IEnumerable; if( enumeration == null ) { - IListSource listSource = value as IListSource; + var listSource = value as IListSource; if( listSource != null ) { enumeration = listSource.GetList(); @@ -203,7 +178,5 @@ namespace Xceed.Wpf.DataGrid return enumeration; } - - private PropertyDescriptor m_propertyDescriptor; } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/ProxyApplyingFilterCriteriasEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/ProxyApplyingFilterCriteriasEventManager.cs deleted file mode 100644 index c0e4e805..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/ProxyApplyingFilterCriteriasEventManager.cs +++ /dev/null @@ -1,87 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal sealed class ProxyApplyingFilterCriteriasEventManager : WeakEventManager - { - #region Constructor - - private ProxyApplyingFilterCriteriasEventManager() - { - } - - #endregion - - #region CurrentManager Private Property - - private static ProxyApplyingFilterCriteriasEventManager CurrentManager - { - get - { - var managerType = typeof( ProxyApplyingFilterCriteriasEventManager ); - var currentManager = ( ProxyApplyingFilterCriteriasEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new ProxyApplyingFilterCriteriasEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - #endregion - - public static void AddListener( DataGridCollectionViewBase source, IWeakEventListener listener ) - { - if( source == null ) - throw new ArgumentNullException( "source" ); - - if( listener == null ) - throw new ArgumentNullException( "listener" ); - - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( DataGridCollectionViewBase source, IWeakEventListener listener ) - { - if( source == null ) - throw new ArgumentNullException( "source" ); - - if( listener == null ) - throw new ArgumentNullException( "listener" ); - - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - var target = ( DataGridCollectionViewBase )source; - target.ProxyApplyingFilterCriterias += new EventHandler( this.DeliverEvent ); - } - - protected override void StopListening( object source ) - { - var target = ( DataGridCollectionViewBase )source; - target.ProxyApplyingFilterCriterias -= new EventHandler( this.DeliverEvent ); - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/ProxyAutoFilterValuesChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/ProxyAutoFilterValuesChangedEventManager.cs deleted file mode 100644 index 2e6760a8..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/ProxyAutoFilterValuesChangedEventManager.cs +++ /dev/null @@ -1,93 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Specialized; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal sealed class ProxyAutoFilterValuesChangedEventManager : WeakEventManager - { - #region Constructor - - private ProxyAutoFilterValuesChangedEventManager() - { - } - - #endregion - - #region CurrentManager Private Property - - private static ProxyAutoFilterValuesChangedEventManager CurrentManager - { - get - { - var managerType = typeof( ProxyAutoFilterValuesChangedEventManager ); - var currentManager = ( ProxyAutoFilterValuesChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new ProxyAutoFilterValuesChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - #endregion - - public static void AddListener( DataGridCollectionViewBase source, IWeakEventListener listener ) - { - if( source == null ) - throw new ArgumentNullException( "source" ); - - if( listener == null ) - throw new ArgumentNullException( "listener" ); - - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( DataGridCollectionViewBase source, IWeakEventListener listener ) - { - if( source == null ) - throw new ArgumentNullException( "source" ); - - if( listener == null ) - throw new ArgumentNullException( "listener" ); - - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - var target = ( DataGridCollectionViewBase )source; - target.ProxyAutoFilterValuesChanged += new NotifyCollectionChangedEventHandler( this.OnEventRaised ); - } - - protected override void StopListening( object source ) - { - var target = ( DataGridCollectionViewBase )source; - target.ProxyAutoFilterValuesChanged -= new NotifyCollectionChangedEventHandler( this.OnEventRaised ); - } - - private void OnEventRaised( object sender, NotifyCollectionChangedEventArgs e ) - { - this.DeliverEvent( sender, e ); - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/QueryAutoFilterDistinctValuesEvent.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/QueryAutoFilterDistinctValuesEvent.cs deleted file mode 100644 index c721f970..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/QueryAutoFilterDistinctValuesEvent.cs +++ /dev/null @@ -1,55 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Xceed.Wpf.DataGrid -{ - internal class QueryAutoFilterDistinctValuesEventArgs : EventArgs - { - internal QueryAutoFilterDistinctValuesEventArgs( DataGridItemPropertyBase itemProperty ) - { - m_itemProperty = itemProperty; - m_distinctValues = new List(); - } - - public DataGridItemPropertyBase ItemProperty - { - get - { - return m_itemProperty; - } - } - - public List DistinctValues - { - get - { - return m_distinctValues; - } - } - - #region PRIVATE FIELDS - - private DataGridItemPropertyBase m_itemProperty; - private List m_distinctValues; - - #endregion PRIVATE FIELDS - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/RawItemSortComparer.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/RawItemSortComparer.cs index 3a007edc..a3decd05 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/RawItemSortComparer.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/RawItemSortComparer.cs @@ -14,10 +14,7 @@ ***********************************************************************************/ -using System; -using System.Collections; using System.Collections.Generic; -using System.Text; using System.ComponentModel; using Xceed.Utils.Data; @@ -36,61 +33,60 @@ namespace Xceed.Wpf.DataGrid public int Compare( RawItem xRawItem, RawItem yRawItem ) { if( xRawItem == null ) - { - if( yRawItem == null ) - { - return 0; - } - else - { - return -1; - } - } - else - { - if( yRawItem == null ) - { - return 1; - } - } + return ( yRawItem == null ) ? 0 : -1; - ListSortDirection lastSortDirection = ListSortDirection.Ascending; - SortDescriptionCollection sortDescriptions = m_collectionView.SortDescriptions; - int sortDescriptionCount = sortDescriptions.Count; + if( yRawItem == null ) + return 1; + + var lastSortDirection = ListSortDirection.Ascending; + var sortDescriptions = m_collectionView.SortDescriptions; + var sortDescriptionCount = sortDescriptions.Count; if( sortDescriptionCount > 0 ) { - int result; - DataGridItemPropertyCollection itemProperties = m_collectionView.ItemProperties; + var result = default( int ); + var itemProperties = m_collectionView.ItemProperties; for( int i = 0; i < sortDescriptionCount; i++ ) { - SortDescription sortDescription = sortDescriptions[ i ]; + var sortDescription = sortDescriptions[ i ]; lastSortDirection = sortDescription.Direction; - DataGridItemPropertyBase dataProperty = itemProperties[ sortDescription.PropertyName ]; - if( dataProperty == null ) + var itemProperty = ItemsSourceHelper.GetItemPropertyFromProperty( itemProperties, sortDescription.PropertyName ); + if( itemProperty == null ) continue; - ISupportInitialize supportInitialize = dataProperty as ISupportInitialize; - object xData = null; - object yData = null; + var supportInitialize = itemProperty as ISupportInitialize; + var xData = default( object ); + var yData = default( object ); if( supportInitialize != null ) + { supportInitialize.BeginInit(); + } try { - xData = dataProperty.GetValue( xRawItem.DataItem ); - yData = dataProperty.GetValue( yRawItem.DataItem ); + xData = ItemsSourceHelper.GetValueFromItemProperty( itemProperty, xRawItem.DataItem ); + yData = ItemsSourceHelper.GetValueFromItemProperty( itemProperty, yRawItem.DataItem ); + + if( itemProperty.IsSortingOnForeignKeyDescription ) + { + var foreignKeyDescription = itemProperty.ForeignKeyDescription; + + xData = foreignKeyDescription.GetDisplayValue( xData ); + yData = foreignKeyDescription.GetDisplayValue( yData ); + } } finally { if( supportInitialize != null ) + { supportInitialize.EndInit(); + } } - IComparer sortComparer = dataProperty.SortComparer; + var sortComparer = itemProperty.SortComparer; if( sortComparer != null ) { @@ -104,7 +100,7 @@ namespace Xceed.Wpf.DataGrid if( result != 0 ) { if( lastSortDirection == ListSortDirection.Descending ) - result = - result; + return -result; return result; } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/RootGroupChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/RootGroupChangedEventManager.cs deleted file mode 100644 index 48f4843f..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/RootGroupChangedEventManager.cs +++ /dev/null @@ -1,87 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal sealed class RootGroupChangedEventManager : WeakEventManager - { - #region Constructor - - private RootGroupChangedEventManager() - { - } - - #endregion - - #region CurrentManager Private Property - - private static RootGroupChangedEventManager CurrentManager - { - get - { - var managerType = typeof( RootGroupChangedEventManager ); - var currentManager = ( RootGroupChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new RootGroupChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - #endregion - - public static void AddListener( DataGridCollectionView source, IWeakEventListener listener ) - { - if( source == null ) - throw new ArgumentNullException( "source" ); - - if( listener == null ) - throw new ArgumentNullException( "listener" ); - - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( DataGridCollectionView source, IWeakEventListener listener ) - { - if( source == null ) - throw new ArgumentNullException( "source" ); - - if( listener == null ) - throw new ArgumentNullException( "listener" ); - - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - var target = ( DataGridCollectionView )source; - target.RootGroupChanged += new EventHandler( this.DeliverEvent ); - } - - protected override void StopListening( object source ) - { - var target = ( DataGridCollectionView )source; - target.RootGroupChanged -= new EventHandler( this.DeliverEvent ); - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/SortedDescriptionInfo.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/SortedDescriptionInfo.cs index bbd9f796..46a87291 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/SortedDescriptionInfo.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/SortedDescriptionInfo.cs @@ -25,14 +25,14 @@ namespace Xceed.Wpf.DataGrid { internal class SortDescriptionInfo { - public SortDescriptionInfo( - DataGridItemPropertyBase property, - ListSortDirection direction ) + public SortDescriptionInfo( DataGridItemPropertyBase property, ListSortDirection direction ) { m_property = property; m_direction = direction; } + #region SortDirection Property + public ListSortDirection SortDirection { get @@ -41,6 +41,10 @@ namespace Xceed.Wpf.DataGrid } } + #endregion + + #region Property Property + public DataGridItemPropertyBase Property { get @@ -49,6 +53,10 @@ namespace Xceed.Wpf.DataGrid } } + #endregion + + #region DataStore Property + public DataStore DataStore { get @@ -61,6 +69,10 @@ namespace Xceed.Wpf.DataGrid } } + #endregion + + #region SortComparer Property + public IComparer SortComparer { get @@ -72,6 +84,8 @@ namespace Xceed.Wpf.DataGrid } } + #endregion + public bool IsReverseOf( SortDescriptionInfo sortDescriptionInfo ) { if( sortDescriptionInfo.m_property == m_property ) diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/UnboundDataItem.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/UnboundDataItem.cs index 298de0f3..aff4b0a8 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/UnboundDataItem.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/UnboundDataItem.cs @@ -14,228 +14,79 @@ ***********************************************************************************/ -using System; +using System.Collections; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; -using System.Diagnostics; +using Xceed.Utils.Collections; namespace Xceed.Wpf.DataGrid { - internal class UnboundDataItem + internal sealed class UnboundDataItem { - #region CONSTRUCTORS + #region Static Fields - private UnboundDataItem( object dataItem ) - { - if( dataItem == null ) - { - m_weakDataItem = null; - } - else - { - m_weakDataItem = new WeakReference( dataItem ); - } - } + private static readonly WeakDictionary s_collection = new WeakDictionary( 0, new Comparer() ); + private static readonly UnboundDataItem s_empty = new UnboundDataItem( null ); - #endregion CONSTRUCTORS + #endregion - public static void FreeUnboundDataItem( UnboundDataItemNode unboundDataItemNode ) + private UnboundDataItem( object dataItem ) { - lock( UnboundDataItem.UnboundDataItems ) - { - UnboundDataItems.Remove( unboundDataItemNode ); - } + m_dataItem = dataItem; } - public static UnboundDataItemNode GetUnboundDataItemNode( object dataItem, out UnboundDataItem unboundDataItem ) - { - lock( UnboundDataItem.UnboundDataItems ) - { - UnboundDataItemNode current = UnboundDataItem.UnboundDataItems.FirstNode; - - while( current != null ) - { - object currentDataItem = current.DataItem; - unboundDataItem = current.UnboundDataItem; - - if( !current.IsAlive ) - { - UnboundDataItemNode next = current.Next; - UnboundDataItem.UnboundDataItems.Remove( current ); - current = next; - continue; - } + #region DataItem Property - if( object.Equals( currentDataItem, dataItem ) ) - return current; - - current = current.Next; - } - - unboundDataItem = new UnboundDataItem( dataItem ); - UnboundDataItemNode unboundDataItemNode = new UnboundDataItemNode( unboundDataItem ); - UnboundDataItem.UnboundDataItems.Add( unboundDataItemNode ); - return unboundDataItemNode; - } - } - - public object DataItem + internal object DataItem { get { - return ( m_weakDataItem == null ) ? null : m_weakDataItem.Target; + return m_dataItem; } } - private WeakReference m_weakDataItem; + private readonly object m_dataItem; - private static UnboundDataItemList UnboundDataItems = new UnboundDataItemList(); + #endregion - internal class UnboundDataItemNode + internal static UnboundDataItem GetUnboundDataItem( object dataItem ) { - public UnboundDataItemNode( UnboundDataItem unboundDataItem ) - { - if( unboundDataItem == null ) - throw new ArgumentNullException( "unboundDataItem" ); - - m_weakUnboundDataItem = new WeakReference( unboundDataItem ); - } - - public object DataItem - { - get - { - UnboundDataItem unboundDataItem = m_weakUnboundDataItem.Target as UnboundDataItem; - - if( unboundDataItem == null ) - return null; + if( dataItem == null ) + return s_empty; - return unboundDataItem.DataItem; - } - } + var value = dataItem as UnboundDataItem; + if( value != null ) + return value; - public UnboundDataItem UnboundDataItem + lock( ( ( ICollection )s_collection ).SyncRoot ) { - get + if( !s_collection.TryGetValue( dataItem, out value ) ) { - if( m_weakUnboundDataItem == null ) - return null; - - return m_weakUnboundDataItem.Target as UnboundDataItem; + value = new UnboundDataItem( dataItem ); + s_collection.Add( dataItem, value ); } - } - - public UnboundDataItemNode Next - { - get; - set; - } - public UnboundDataItemNode Previous - { - get; - set; + return value; } - - public bool IsAlive - { - get - { - UnboundDataItem unboundDataItem = m_weakUnboundDataItem.Target as UnboundDataItem; - - if( unboundDataItem == null ) - return false; - - WeakReference weakDataItem = unboundDataItem.m_weakDataItem; - - return ( ( weakDataItem == null ) || ( weakDataItem.IsAlive ) ) - && ( m_weakUnboundDataItem.IsAlive ); - } - } - - private WeakReference m_weakUnboundDataItem; } - private class UnboundDataItemList - { - public void Add( UnboundDataItemNode newNode ) - { - newNode.Next = this.FirstNode; - - if( this.FirstNode != null ) - this.FirstNode.Previous = newNode; - - this.FirstNode = newNode; - - if( this.LastNode == null ) - this.LastNode = this.FirstNode; - - m_count++; - } - - public void Remove( UnboundDataItemNode unboundDataItemNode ) - { - bool removed = false; - - if( this.LastNode == unboundDataItemNode ) - { - this.LastNode = unboundDataItemNode.Previous; - removed = true; - } - - if( this.FirstNode == unboundDataItemNode ) - { - this.FirstNode = unboundDataItemNode.Next; - removed = true; - } - - UnboundDataItemNode previous = unboundDataItemNode.Previous; - - if( previous != null ) - { - previous.Next = unboundDataItemNode.Next; - removed = true; - } - - UnboundDataItemNode next = unboundDataItemNode.Next; - - if( next != null ) - { - next.Previous = unboundDataItemNode.Previous; - removed = true; - } - - if( removed ) - { - unboundDataItemNode.Previous = null; - unboundDataItemNode.Next = null; - m_count--; - } - } + #region Comparer Private Class - public UnboundDataItemNode FirstNode + private sealed class Comparer : IEqualityComparer + { + int IEqualityComparer.GetHashCode( object obj ) { - get; - private set; - } + if( obj == null ) + return 0; - public UnboundDataItemNode LastNode - { - get; - private set; + return obj.GetHashCode(); } - public int Count + bool IEqualityComparer.Equals( object x, object y ) { - get - { - return m_count; - } + return object.Equals( x, y ); } - - private int m_count; } + + #endregion } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/AddingNewDataItemEvent.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/AddingNewDataItemEventArgs.cs similarity index 92% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/AddingNewDataItemEvent.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/AddingNewDataItemEventArgs.cs index 96749574..54ee691c 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/AddingNewDataItemEvent.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/AddingNewDataItemEventArgs.cs @@ -1,47 +1,45 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.ComponentModel; - -namespace Xceed.Wpf.DataGrid -{ - [Obsolete( "The AddingNewDataItem event is obsolete and has been replaced by the DataGridCollectionView.InsertingNewItem and InitializingNewItem events.", false )] - [Browsable( false )] - [EditorBrowsable( EditorBrowsableState.Never )] - public class AddingNewDataItemEventArgs : EventArgs - { - public AddingNewDataItemEventArgs() - { - } - - public object DataItem - { - get - { - return m_dataItem; - } - set - { - m_dataItem = value; - } - } - - private object m_dataItem; - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.ComponentModel; + +namespace Xceed.Wpf.DataGrid +{ + [Obsolete( "The AddingNewDataItem event is obsolete and has been replaced by the DataGridCollectionView.InsertingNewItem and InitializingNewItem events.", false )] + [Browsable( false )] + [EditorBrowsable( EditorBrowsableState.Never )] + public class AddingNewDataItemEventArgs : EventArgs + { + public AddingNewDataItemEventArgs() + { + } + + public object DataItem + { + get + { + return m_dataItem; + } + set + { + m_dataItem = value; + } + } + + private object m_dataItem; + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/AllowDetailToggleChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/AllowDetailToggleChangedEventManager.cs similarity index 88% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/AllowDetailToggleChangedEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/AllowDetailToggleChangedEventManager.cs index 19df22da..97ee3092 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/AllowDetailToggleChangedEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/AllowDetailToggleChangedEventManager.cs @@ -1,100 +1,94 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class AllowDetailToggleChangedEventManager : WeakEventManager - { - private AllowDetailToggleChangedEventManager() - { - } - - public static void AddListener( object source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( object source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - DataGridControl dataGridControl = source as DataGridControl; - if( dataGridControl != null ) - { - dataGridControl.AllowDetailToggleChanged += new EventHandler( this.OnAllowDetailToggleChanged ); - return; - } - - DetailConfiguration detailConfiguration = source as DetailConfiguration; - if( detailConfiguration != null ) - { - detailConfiguration.AllowDetailToggleChanged += new EventHandler( this.OnAllowDetailToggleChanged ); - return; - } - - throw new ArgumentException( "The specified source must be a DataGridControl or a DetailConfiguration.", "source" ); - } - - protected override void StopListening( object source ) - { - DataGridControl dataGridControl = source as DataGridControl; - if( dataGridControl != null ) - { - dataGridControl.AllowDetailToggleChanged -= new EventHandler( this.OnAllowDetailToggleChanged ); - return; - } - - DetailConfiguration detailConfiguration = source as DetailConfiguration; - if( detailConfiguration != null ) - { - detailConfiguration.AllowDetailToggleChanged -= new EventHandler( this.OnAllowDetailToggleChanged ); - return; - } - - throw new ArgumentException( "The specified source must be a DataGridControl or a DetailConfiguration.", "source" ); - } - - private static AllowDetailToggleChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( AllowDetailToggleChangedEventManager ); - AllowDetailToggleChangedEventManager currentManager = ( AllowDetailToggleChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new AllowDetailToggleChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnAllowDetailToggleChanged( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class AllowDetailToggleChangedEventManager : WeakEventManager + { + internal static void AddListener( object source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( object source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + DataGridControl dataGridControl = source as DataGridControl; + if( dataGridControl != null ) + { + dataGridControl.AllowDetailToggleChanged += new EventHandler( this.OnAllowDetailToggleChanged ); + return; + } + + DetailConfiguration detailConfiguration = source as DetailConfiguration; + if( detailConfiguration != null ) + { + detailConfiguration.AllowDetailToggleChanged += new EventHandler( this.OnAllowDetailToggleChanged ); + return; + } + + throw new ArgumentException( "The specified source must be a DataGridControl or a DetailConfiguration.", "source" ); + } + + protected override void StopListening( object source ) + { + DataGridControl dataGridControl = source as DataGridControl; + if( dataGridControl != null ) + { + dataGridControl.AllowDetailToggleChanged -= new EventHandler( this.OnAllowDetailToggleChanged ); + return; + } + + DetailConfiguration detailConfiguration = source as DetailConfiguration; + if( detailConfiguration != null ) + { + detailConfiguration.AllowDetailToggleChanged -= new EventHandler( this.OnAllowDetailToggleChanged ); + return; + } + + throw new ArgumentException( "The specified source must be a DataGridControl or a DetailConfiguration.", "source" ); + } + + private static AllowDetailToggleChangedEventManager CurrentManager + { + get + { + Type managerType = typeof( AllowDetailToggleChangedEventManager ); + AllowDetailToggleChangedEventManager currentManager = ( AllowDetailToggleChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new AllowDetailToggleChangedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnAllowDetailToggleChanged( object sender, EventArgs args ) + { + this.DeliverEvent( sender, args ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/QueryHelpTextRoutedEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/CancelRoutedEvent.cs similarity index 53% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/QueryHelpTextRoutedEventArgs.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/CancelRoutedEvent.cs index ec8b4dc8..972f097d 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/QueryHelpTextRoutedEventArgs.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/CancelRoutedEvent.cs @@ -1,44 +1,59 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid.Automation -{ - public delegate void QueryHelpTextRoutedEventHandler( object sender, QueryHelpTextRoutedEventArgs e ); - - public class QueryHelpTextRoutedEventArgs : RoutedEventArgs - { - public QueryHelpTextRoutedEventArgs( RoutedEvent routedEvent, object source ) - : base( routedEvent, source ) - { - } - - #region HelpText Property - - public string HelpText - { - get; - set; - } - - #endregion - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + public delegate void CancelRoutedEventHandler( object sender, CancelRoutedEventArgs e ); + + public class CancelRoutedEventArgs : RoutedEventArgs + { + public CancelRoutedEventArgs() + : base() + { + } + + public CancelRoutedEventArgs( RoutedEvent routedEvent ) + : base( routedEvent ) + { + } + + public CancelRoutedEventArgs( RoutedEvent routedEvent, object source ) + : base( routedEvent, source ) + { + } + + #region Cancel PROPERTY + + public bool Cancel + { + get + { + return m_cancel; + } + + set + { + m_cancel = value; + } + } + + private bool m_cancel; + + #endregion Cancel PROPERTY + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellValidatingEvent.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/CellValidatingEventArgs.cs similarity index 88% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellValidatingEvent.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/CellValidatingEventArgs.cs index ad840462..0ce4b2d7 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellValidatingEvent.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/CellValidatingEventArgs.cs @@ -1,83 +1,81 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows.Controls; -using System.Globalization; - -namespace Xceed.Wpf.DataGrid -{ - public class CellValidatingEventArgs : EventArgs - { - public CellValidatingEventArgs( - object value, - CultureInfo culture, - CellValidationContext context ) - { - m_value = value; - m_culture = culture; - m_context = context; - } - - public object Value - { - get - { - return m_value; - } - } - - public CultureInfo Culture - { - get - { - return m_culture; - } - } - - public CellValidationContext Context - { - get - { - return m_context; - } - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly" )] - public ValidationResult Result - { - get - { - return m_validationResult; - } - - set - { - if( value == null ) - throw new ArgumentNullException( "Result" ); - - m_validationResult = value; - } - } - - object m_value; - CultureInfo m_culture; - CellValidationContext m_context; - ValidationResult m_validationResult = ValidationResult.ValidResult; - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Globalization; +using System.Windows.Controls; + +namespace Xceed.Wpf.DataGrid +{ + public class CellValidatingEventArgs : EventArgs + { + public CellValidatingEventArgs( + object value, + CultureInfo culture, + CellValidationContext context ) + { + m_value = value; + m_culture = culture; + m_context = context; + } + + public object Value + { + get + { + return m_value; + } + } + + public CultureInfo Culture + { + get + { + return m_culture; + } + } + + public CellValidationContext Context + { + get + { + return m_context; + } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly" )] + public ValidationResult Result + { + get + { + return m_validationResult; + } + + set + { + if( value == null ) + throw new ArgumentNullException( "Result" ); + + m_validationResult = value; + } + } + + object m_value; + CultureInfo m_culture; + CellValidationContext m_context; + ValidationResult m_validationResult = ValidationResult.ValidResult; + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellValidationErrorRoutedEvent.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/CellValidationErrorRoutedEvent.cs similarity index 95% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellValidationErrorRoutedEvent.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/CellValidationErrorRoutedEvent.cs index b361e3ee..51376a50 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellValidationErrorRoutedEvent.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/CellValidationErrorRoutedEvent.cs @@ -1,68 +1,67 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Windows; -using System.Windows.Controls; - -namespace Xceed.Wpf.DataGrid -{ - public delegate void CellValidationErrorRoutedEventHandler( object sender, CellValidationErrorRoutedEventArgs e ); - - public class CellValidationErrorRoutedEventArgs : RoutedEventArgs - { - public CellValidationErrorRoutedEventArgs( CellValidationError cellValidationError ) - : base() - { - if( cellValidationError == null ) - throw new ArgumentNullException( "cellValidationError" ); - - m_cellValidationError = cellValidationError; - } - - public CellValidationErrorRoutedEventArgs( RoutedEvent routedEvent, CellValidationError cellValidationError ) - : base( routedEvent ) - { - if( cellValidationError == null ) - throw new ArgumentNullException( "cellValidationError" ); - - m_cellValidationError = cellValidationError; - } - - public CellValidationErrorRoutedEventArgs( RoutedEvent routedEvent, object source, CellValidationError cellValidationError ) - : base( routedEvent, source ) - { - if( cellValidationError == null ) - throw new ArgumentNullException( "cellValidationError" ); - - m_cellValidationError = cellValidationError; - } - - #region CellValidationError PROPERTY - - public CellValidationError CellValidationError - { - get - { - return m_cellValidationError; - } - } - - private CellValidationError m_cellValidationError; - - #endregion CellValidationError PROPERTY - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + public delegate void CellValidationErrorRoutedEventHandler( object sender, CellValidationErrorRoutedEventArgs e ); + + public class CellValidationErrorRoutedEventArgs : RoutedEventArgs + { + public CellValidationErrorRoutedEventArgs( CellValidationError cellValidationError ) + : base() + { + if( cellValidationError == null ) + throw new ArgumentNullException( "cellValidationError" ); + + m_cellValidationError = cellValidationError; + } + + public CellValidationErrorRoutedEventArgs( RoutedEvent routedEvent, CellValidationError cellValidationError ) + : base( routedEvent ) + { + if( cellValidationError == null ) + throw new ArgumentNullException( "cellValidationError" ); + + m_cellValidationError = cellValidationError; + } + + public CellValidationErrorRoutedEventArgs( RoutedEvent routedEvent, object source, CellValidationError cellValidationError ) + : base( routedEvent, source ) + { + if( cellValidationError == null ) + throw new ArgumentNullException( "cellValidationError" ); + + m_cellValidationError = cellValidationError; + } + + #region CellValidationError PROPERTY + + public CellValidationError CellValidationError + { + get + { + return m_cellValidationError; + } + } + + private CellValidationError m_cellValidationError; + + #endregion CellValidationError PROPERTY + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ColumnActualWidthChangedHandler.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ColumnActualWidthChangedEvent.cs similarity index 72% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ColumnActualWidthChangedHandler.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ColumnActualWidthChangedEvent.cs index 25f13c97..4df0ddf5 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ColumnActualWidthChangedHandler.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ColumnActualWidthChangedEvent.cs @@ -1,63 +1,60 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Xceed.Wpf.DataGrid -{ - internal class ColumnActualWidthChangedEventArgs : EventArgs - { - public ColumnActualWidthChangedEventArgs( ColumnBase column , double oldValue, double newValue ) - { - m_column = column; - m_oldValue = oldValue; - m_newValue = newValue; - } - - public ColumnBase Column - { - get - { - return m_column; - } - } - - public double NewValue - { - get - { - return m_newValue; - } - } - - public double OldValue - { - get - { - return m_oldValue; - } - } - - private ColumnBase m_column; - private double m_oldValue; - private double m_newValue; - } - - internal delegate void ColumnActualWidthChangedHandler( object sender, ColumnActualWidthChangedEventArgs e ); -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; + +namespace Xceed.Wpf.DataGrid +{ + internal class ColumnActualWidthChangedEventArgs : EventArgs + { + internal ColumnActualWidthChangedEventArgs( ColumnBase column, double oldValue, double newValue ) + { + m_column = column; + m_oldValue = oldValue; + m_newValue = newValue; + } + + internal ColumnBase Column + { + get + { + return m_column; + } + } + + internal double NewValue + { + get + { + return m_newValue; + } + } + + internal double OldValue + { + get + { + return m_oldValue; + } + } + + private ColumnBase m_column; + private double m_oldValue; + private double m_newValue; + } + + internal delegate void ColumnActualWidthChangedEventHandler( object sender, ColumnActualWidthChangedEventArgs e ); +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ColumnActualWidthEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ColumnActualWidthEventManager.cs similarity index 81% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ColumnActualWidthEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ColumnActualWidthEventManager.cs index 396dcd11..b06c6463 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ColumnActualWidthEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ColumnActualWidthEventManager.cs @@ -1,74 +1,68 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class ColumnActualWidthEventManager : WeakEventManager - { - private ColumnActualWidthEventManager() - { - } - - public static void AddListener( ColumnCollection source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( ColumnCollection source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - ColumnCollection columns = ( ColumnCollection )source; - columns.ActualWidthChanged += new ColumnActualWidthChangedHandler( this.OnActualWidthChanged ); - } - - protected override void StopListening( object source ) - { - ColumnCollection columns = ( ColumnCollection )source; - columns.ActualWidthChanged -= new ColumnActualWidthChangedHandler( this.OnActualWidthChanged ); - } - - private static ColumnActualWidthEventManager CurrentManager - { - get - { - Type managerType = typeof( ColumnActualWidthEventManager ); - ColumnActualWidthEventManager currentManager = ( ColumnActualWidthEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new ColumnActualWidthEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnActualWidthChanged( object sender, ColumnActualWidthChangedEventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class ColumnActualWidthEventManager : WeakEventManager + { + internal static void AddListener( ColumnCollection source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( ColumnCollection source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + ColumnCollection columns = ( ColumnCollection )source; + columns.ActualWidthChanged += new ColumnActualWidthChangedEventHandler( this.OnActualWidthChanged ); + } + + protected override void StopListening( object source ) + { + ColumnCollection columns = ( ColumnCollection )source; + columns.ActualWidthChanged -= new ColumnActualWidthChangedEventHandler( this.OnActualWidthChanged ); + } + + private static ColumnActualWidthEventManager CurrentManager + { + get + { + Type managerType = typeof( ColumnActualWidthEventManager ); + ColumnActualWidthEventManager currentManager = ( ColumnActualWidthEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new ColumnActualWidthEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnActualWidthChanged( object sender, ColumnActualWidthChangedEventArgs args ) + { + this.DeliverEvent( sender, args ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ColumnSortDirectionChangingEvent.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ColumnSortDirectionChangingEvent.cs new file mode 100644 index 00000000..f89fe7ba --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ColumnSortDirectionChangingEvent.cs @@ -0,0 +1,98 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + public delegate void ColumnSortDirectionChangingEventHandler( object sender, ColumnSortDirectionChangingEventArgs e ); + + public class ColumnSortDirectionChangingEventArgs : RoutedEventArgs + { + public ColumnSortDirectionChangingEventArgs( RoutedEvent routedEvent, ColumnBase column, DataGridContext dataGridContext, SortDirection currentSortDirection, SortDirection nextSortDirection ) + : base( routedEvent, column ) + { + if( column == null ) + throw new ArgumentNullException( "column" ); + + if( dataGridContext == null ) + throw new ArgumentNullException( "dataGridContext" ); + + m_dataGridContext = dataGridContext; + m_current = currentSortDirection; + m_next = nextSortDirection; + } + + #region Column Property + + public ColumnBase Column + { + get + { + return ( ColumnBase )this.OriginalSource; + } + } + + #endregion + + #region DataGridContext Property + + public DataGridContext DataGridContext + { + get + { + return m_dataGridContext; + } + } + + private DataGridContext m_dataGridContext; + + #endregion + + #region CurrentSortDirection Property + + public SortDirection CurrentSortDirection + { + get + { + return m_current; + } + } + + private SortDirection m_current; + + #endregion + + #region NextSortDirection Property + + public SortDirection NextSortDirection + { + get + { + return m_next; + } + set + { + m_next = value; + } + } + + private SortDirection m_next; + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnVisibilePositionChangedEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ColumnVisibilePositionChangedEventArgs.cs similarity index 72% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnVisibilePositionChangedEventArgs.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ColumnVisibilePositionChangedEventArgs.cs index b7c73ddd..bc121bd9 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnVisibilePositionChangedEventArgs.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ColumnVisibilePositionChangedEventArgs.cs @@ -1,64 +1,50 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; - -namespace Xceed.Wpf.DataGrid -{ - internal class ColumnVisiblePositionChangedEventArgs : EventArgs - { - #region PUBLIC CONTRUCTORS - - public ColumnVisiblePositionChangedEventArgs( ColumnBase triggeringColumn, int oldPosition, int newPosition ) - { - m_triggeringColumn = triggeringColumn; - m_newPosition = newPosition; - m_oldPosition = oldPosition; - } - - #endregion - - #region PUBLIC PROPERTIES - - public ColumnBase TriggeringColumn - { - get - { - return m_triggeringColumn; - } - } - - public int PositionDelta - { - get - { - return m_newPosition - m_oldPosition; - } - } - - #endregion - - #region PRIVATE FIELDS - - private ColumnBase m_triggeringColumn; - private int m_newPosition; - private int m_oldPosition; - - #endregion - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; + +namespace Xceed.Wpf.DataGrid +{ + internal class ColumnVisiblePositionChangedEventArgs : EventArgs + { + internal ColumnVisiblePositionChangedEventArgs( ColumnBase triggeringColumn, int oldPosition, int newPosition ) + { + m_triggeringColumn = triggeringColumn; + m_newPosition = newPosition; + m_oldPosition = oldPosition; + } + + internal ColumnBase TriggeringColumn + { + get + { + return m_triggeringColumn; + } + } + + internal int PositionDelta + { + get + { + return m_newPosition - m_oldPosition; + } + } + + private ColumnBase m_triggeringColumn; + private int m_newPosition; + private int m_oldPosition; + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ColumnsLayoutChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ColumnsLayoutChangedEventManager.cs new file mode 100644 index 00000000..7245ae74 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ColumnsLayoutChangedEventManager.cs @@ -0,0 +1,66 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal sealed class ColumnsLayoutChangedEventManager : WeakEventManager + { + internal static void AddListener( ColumnHierarchyManager source, IWeakEventListener listener ) + { + ColumnsLayoutChangedEventManager.CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( ColumnHierarchyManager source, IWeakEventListener listener ) + { + ColumnsLayoutChangedEventManager.CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + ( ( ColumnHierarchyManager )source ).LayoutChanged += new EventHandler( this.OnEventRaised ); + } + + protected override void StopListening( object source ) + { + ( ( ColumnHierarchyManager )source ).LayoutChanged -= new EventHandler( this.OnEventRaised ); + } + + private static ColumnsLayoutChangedEventManager CurrentManager + { + get + { + var managerType = typeof( ColumnsLayoutChangedEventManager ); + var currentManager = ( ColumnsLayoutChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new ColumnsLayoutChangedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnEventRaised( object sender, EventArgs e ) + { + this.DeliverEvent( sender, e ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ColumnsLayoutChangingEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ColumnsLayoutChangingEventManager.cs new file mode 100644 index 00000000..1446319b --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ColumnsLayoutChangingEventManager.cs @@ -0,0 +1,66 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal sealed class ColumnsLayoutChangingEventManager : WeakEventManager + { + internal static void AddListener( ColumnHierarchyManager source, IWeakEventListener listener ) + { + ColumnsLayoutChangingEventManager.CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( ColumnHierarchyManager source, IWeakEventListener listener ) + { + ColumnsLayoutChangingEventManager.CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + ( ( ColumnHierarchyManager )source ).LayoutChanging += new EventHandler( this.OnEventRaised ); + } + + protected override void StopListening( object source ) + { + ( ( ColumnHierarchyManager )source ).LayoutChanging -= new EventHandler( this.OnEventRaised ); + } + + private static ColumnsLayoutChangingEventManager CurrentManager + { + get + { + var managerType = typeof( ColumnsLayoutChangingEventManager ); + var currentManager = ( ColumnsLayoutChangingEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new ColumnsLayoutChangingEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnEventRaised( object sender, EventArgs e ) + { + this.DeliverEvent( sender, e ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/CurrentColumnChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/CurrentColumnChangedEventManager.cs similarity index 81% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/CurrentColumnChangedEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/CurrentColumnChangedEventManager.cs index 7567acf3..3f7fe457 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/CurrentColumnChangedEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/CurrentColumnChangedEventManager.cs @@ -1,74 +1,68 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class CurrentColumnChangedEventManager: WeakEventManager - { - private CurrentColumnChangedEventManager() - { - } - - public static void AddListener( DetailConfiguration source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( DetailConfiguration source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - DetailConfiguration detailConfig = ( DetailConfiguration )source; - detailConfig.CurrentColumnChanged += new EventHandler( this.OnCurrentColumnChanged ); - } - - protected override void StopListening( object source ) - { - DetailConfiguration detailConfig = ( DetailConfiguration )source; - detailConfig.CurrentColumnChanged -= new EventHandler( this.OnCurrentColumnChanged ); - } - - private static CurrentColumnChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( CurrentColumnChangedEventManager ); - CurrentColumnChangedEventManager currentManager = ( CurrentColumnChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new CurrentColumnChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnCurrentColumnChanged( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class CurrentColumnChangedEventManager : WeakEventManager + { + internal static void AddListener( DetailConfiguration source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( DetailConfiguration source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + DetailConfiguration detailConfig = ( DetailConfiguration )source; + detailConfig.CurrentColumnChanged += new EventHandler( this.OnCurrentColumnChanged ); + } + + protected override void StopListening( object source ) + { + DetailConfiguration detailConfig = ( DetailConfiguration )source; + detailConfig.CurrentColumnChanged -= new EventHandler( this.OnCurrentColumnChanged ); + } + + private static CurrentColumnChangedEventManager CurrentManager + { + get + { + Type managerType = typeof( CurrentColumnChangedEventManager ); + CurrentColumnChangedEventManager currentManager = ( CurrentColumnChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new CurrentColumnChangedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnCurrentColumnChanged( object sender, EventArgs args ) + { + this.DeliverEvent( sender, args ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/CurrentItemChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/CurrentItemChangedEventManager.cs new file mode 100644 index 00000000..c9fc90c9 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/CurrentItemChangedEventManager.cs @@ -0,0 +1,66 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal sealed class CurrentItemChangedEventManager : WeakEventManager + { + internal static void AddListener( DataGridContext source, IWeakEventListener listener ) + { + CurrentItemChangedEventManager.CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( DataGridContext source, IWeakEventListener listener ) + { + CurrentItemChangedEventManager.CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + ( ( DataGridContext )source ).CurrentItemChanged += new EventHandler( this.OnEventRaised ); + } + + protected override void StopListening( object source ) + { + ( ( DataGridContext )source ).CurrentItemChanged -= new EventHandler( this.OnEventRaised ); + } + + private static CurrentItemChangedEventManager CurrentManager + { + get + { + var managerType = typeof( CurrentItemChangedEventManager ); + var currentManager = ( CurrentItemChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new CurrentItemChangedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnEventRaised( object sender, EventArgs e ) + { + this.DeliverEvent( sender, e ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridControlSelectionChangedWeakEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DataGridControlSelectionChangedEventManager.cs similarity index 67% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridControlSelectionChangedWeakEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DataGridControlSelectionChangedEventManager.cs index e7c795d2..783432d8 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridControlSelectionChangedWeakEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DataGridControlSelectionChangedEventManager.cs @@ -1,80 +1,73 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class DataGridControlSelectionChangedWeakEventManager : WeakEventManager - { - private DataGridControlSelectionChangedWeakEventManager() - { - } - - public static void AddListener( DataGridControl source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( DataGridControl source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - DataGridControl dataGridControl = source as DataGridControl; - - if( dataGridControl != null ) - dataGridControl.SelectionChanged += this.DataGridControl_SelectionChanged; - } - - protected override void StopListening( object source ) - { - DataGridControl dataGridControl = source as DataGridControl; - - if( dataGridControl != null ) - dataGridControl.SelectionChanged -= this.DataGridControl_SelectionChanged; - } - - private static DataGridControlSelectionChangedWeakEventManager CurrentManager - { - get - { - Type managerType = typeof( DataGridControlSelectionChangedWeakEventManager ); - DataGridControlSelectionChangedWeakEventManager currentManager = - ( DataGridControlSelectionChangedWeakEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new DataGridControlSelectionChangedWeakEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void DataGridControl_SelectionChanged( object sender, DataGridSelectionChangedEventArgs e ) - { - this.DeliverEvent( sender, e ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class DataGridControlSelectionChangedEventManager : WeakEventManager + { + internal static void AddListener( DataGridControl source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( DataGridControl source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + DataGridControl dataGridControl = source as DataGridControl; + + if( dataGridControl != null ) + dataGridControl.SelectionChanged += this.DataGridControl_SelectionChanged; + } + + protected override void StopListening( object source ) + { + DataGridControl dataGridControl = source as DataGridControl; + + if( dataGridControl != null ) + dataGridControl.SelectionChanged -= this.DataGridControl_SelectionChanged; + } + + private static DataGridControlSelectionChangedEventManager CurrentManager + { + get + { + Type managerType = typeof( DataGridControlSelectionChangedEventManager ); + DataGridControlSelectionChangedEventManager currentManager = + ( DataGridControlSelectionChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new DataGridControlSelectionChangedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void DataGridControl_SelectionChanged( object sender, DataGridSelectionChangedEventArgs e ) + { + this.DeliverEvent( sender, e ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridControlTemplateChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DataGridControlTemplateChangedEventManager.cs similarity index 86% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridControlTemplateChangedEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DataGridControlTemplateChangedEventManager.cs index 59b4f515..7c26c53f 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridControlTemplateChangedEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DataGridControlTemplateChangedEventManager.cs @@ -1,87 +1,80 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class DataGridControlTemplateChangedEventManager : WeakEventManager - { - private DataGridControlTemplateChangedEventManager() - { - } - - public static void AddListener( object source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( object source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - DataGridControl dataGridControl = source as DataGridControl; - if( dataGridControl != null ) - { - dataGridControl.TemplateApplied += new EventHandler( this.OnTemplateApplied ); - return; - } - - throw new ArgumentException( "The specified source must be a DataGridControl.", "source" ); - } - - protected override void StopListening( object source ) - { - DataGridControl dataGridControl = source as DataGridControl; - if( dataGridControl != null ) - { - dataGridControl.TemplateApplied -= new EventHandler( this.OnTemplateApplied ); - return; - } - - throw new ArgumentException( "The specified source must be a DataGridControl.", "source" ); - } - - private static DataGridControlTemplateChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( DataGridControlTemplateChangedEventManager ); - DataGridControlTemplateChangedEventManager currentManager = ( DataGridControlTemplateChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new DataGridControlTemplateChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnTemplateApplied( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class DataGridControlTemplateChangedEventManager : WeakEventManager + { + internal static void AddListener( object source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( object source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + DataGridControl dataGridControl = source as DataGridControl; + if( dataGridControl != null ) + { + dataGridControl.TemplateApplied += new EventHandler( this.OnTemplateApplied ); + return; + } + + throw new ArgumentException( "The specified source must be a DataGridControl.", "source" ); + } + + protected override void StopListening( object source ) + { + DataGridControl dataGridControl = source as DataGridControl; + if( dataGridControl != null ) + { + dataGridControl.TemplateApplied -= new EventHandler( this.OnTemplateApplied ); + return; + } + + throw new ArgumentException( "The specified source must be a DataGridControl.", "source" ); + } + + private static DataGridControlTemplateChangedEventManager CurrentManager + { + get + { + Type managerType = typeof( DataGridControlTemplateChangedEventManager ); + DataGridControlTemplateChangedEventManager currentManager = ( DataGridControlTemplateChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new DataGridControlTemplateChangedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnTemplateApplied( object sender, EventArgs args ) + { + this.DeliverEvent( sender, args ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridCurrentChangedEvent.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DataGridCurrentChangedEvent.cs similarity index 91% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridCurrentChangedEvent.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DataGridCurrentChangedEvent.cs index ecb0e508..1d9de1ae 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridCurrentChangedEvent.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DataGridCurrentChangedEvent.cs @@ -1,62 +1,58 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - public delegate void DataGridCurrentChangedEventHandler( object sender, DataGridCurrentChangedEventArgs e ); - - public class DataGridCurrentChangedEventArgs : RoutedEventArgs - { - internal DataGridCurrentChangedEventArgs( DataGridContext oldDataGridContext, object oldCurrent, DataGridContext newDataGridContext, object newCurrent ) - : base( DataGridControl.CurrentChangedEvent ) - { - this.OldDataGridContext = oldDataGridContext; - this.OldCurrent = oldCurrent; - this.NewDataGridContext = newDataGridContext; - this.NewCurrent = newCurrent; - } - - public DataGridContext OldDataGridContext - { - get; - private set; - } - - public object OldCurrent - { - get; - private set; - } - - public DataGridContext NewDataGridContext - { - get; - private set; - } - - public object NewCurrent - { - get; - private set; - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + public delegate void DataGridCurrentChangedEventHandler( object sender, DataGridCurrentChangedEventArgs e ); + + public class DataGridCurrentChangedEventArgs : RoutedEventArgs + { + internal DataGridCurrentChangedEventArgs( DataGridContext oldDataGridContext, object oldCurrent, DataGridContext newDataGridContext, object newCurrent ) + : base( DataGridControl.CurrentChangedEvent ) + { + this.OldDataGridContext = oldDataGridContext; + this.OldCurrent = oldCurrent; + this.NewDataGridContext = newDataGridContext; + this.NewCurrent = newCurrent; + } + + public DataGridContext OldDataGridContext + { + get; + private set; + } + + public object OldCurrent + { + get; + private set; + } + + public DataGridContext NewDataGridContext + { + get; + private set; + } + + public object NewCurrent + { + get; + private set; + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridCurrentChangingEvent.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DataGridCurrentChangingEvent.cs similarity index 90% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridCurrentChangingEvent.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DataGridCurrentChangingEvent.cs index 1d6eaf2f..2c828e7a 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridCurrentChangingEvent.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DataGridCurrentChangingEvent.cs @@ -1,69 +1,63 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Xceed.Wpf.Toolkit.Core; - -namespace Xceed.Wpf.DataGrid -{ - public delegate void DataGridCurrentChangingEventHandler( object sender, DataGridCurrentChangingEventArgs e ); - - public class DataGridCurrentChangingEventArgs : CancelRoutedEventArgs - { - internal DataGridCurrentChangingEventArgs( DataGridContext oldDataGridContext, object oldCurrent, DataGridContext newDataGridContext, object newCurrent, bool isCancelable ) - : base( DataGridControl.CurrentChangingEvent ) - { - this.IsCancelable = isCancelable; - this.OldDataGridContext = oldDataGridContext; - this.OldCurrent = oldCurrent; - this.NewDataGridContext = newDataGridContext; - this.NewCurrent = newCurrent; - } - - public bool IsCancelable - { - get; - private set; - } - - public DataGridContext OldDataGridContext - { - get; - private set; - } - - public object OldCurrent - { - get; - private set; - } - - public DataGridContext NewDataGridContext - { - get; - private set; - } - - public object NewCurrent - { - get; - private set; - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +namespace Xceed.Wpf.DataGrid +{ + public delegate void DataGridCurrentChangingEventHandler( object sender, DataGridCurrentChangingEventArgs e ); + + public class DataGridCurrentChangingEventArgs : CancelRoutedEventArgs + { + internal DataGridCurrentChangingEventArgs( DataGridContext oldDataGridContext, object oldCurrent, DataGridContext newDataGridContext, object newCurrent, bool isCancelable ) + : base( DataGridControl.CurrentChangingEvent ) + { + this.IsCancelable = isCancelable; + this.OldDataGridContext = oldDataGridContext; + this.OldCurrent = oldCurrent; + this.NewDataGridContext = newDataGridContext; + this.NewCurrent = newCurrent; + } + + public bool IsCancelable + { + get; + private set; + } + + public DataGridContext OldDataGridContext + { + get; + private set; + } + + public object OldCurrent + { + get; + private set; + } + + public DataGridContext NewDataGridContext + { + get; + private set; + } + + public object NewCurrent + { + get; + private set; + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridSelectionChangedEvent.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DataGridSelectionChangedEvent.cs similarity index 95% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridSelectionChangedEvent.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DataGridSelectionChangedEvent.cs index 4c17ee17..13f6576e 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridSelectionChangedEvent.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DataGridSelectionChangedEvent.cs @@ -1,39 +1,38 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - public delegate void DataGridSelectionChangedEventHandler( object sender, DataGridSelectionChangedEventArgs e ); - - public class DataGridSelectionChangedEventArgs : RoutedEventArgs - { - internal DataGridSelectionChangedEventArgs( IList selectionInfos ) - : base( DataGridControl.SelectionChangedEvent ) - { - this.SelectionInfos = selectionInfos; - } - - public IList SelectionInfos - { - get; - private set; - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System.Collections.Generic; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + public delegate void DataGridSelectionChangedEventHandler( object sender, DataGridSelectionChangedEventArgs e ); + + public class DataGridSelectionChangedEventArgs : RoutedEventArgs + { + internal DataGridSelectionChangedEventArgs( IList selectionInfos ) + : base( DataGridControl.SelectionChangedEvent ) + { + this.SelectionInfos = selectionInfos; + } + + public IList SelectionInfos + { + get; + private set; + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridSelectionChangingEvent.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DataGridSelectionChangingEvent.cs similarity index 91% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridSelectionChangingEvent.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DataGridSelectionChangingEvent.cs index 8e2734f6..c2cd8b0f 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridSelectionChangingEvent.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DataGridSelectionChangingEvent.cs @@ -1,47 +1,44 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Windows; -using Xceed.Wpf.Toolkit.Core; - -namespace Xceed.Wpf.DataGrid -{ - public delegate void DataGridSelectionChangingEventHandler( object sender, DataGridSelectionChangingEventArgs e ); - - public class DataGridSelectionChangingEventArgs : CancelRoutedEventArgs - { - internal DataGridSelectionChangingEventArgs( IList selectionInfos, bool isCancelable ) - : base( DataGridControl.SelectionChangingEvent ) - { - this.SelectionInfos = selectionInfos; - this.IsCancelable = isCancelable; - } - - public bool IsCancelable - { - get; - private set; - } - - public IList SelectionInfos - { - get; - private set; - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System.Collections.Generic; + +namespace Xceed.Wpf.DataGrid +{ + public delegate void DataGridSelectionChangingEventHandler( object sender, DataGridSelectionChangingEventArgs e ); + + public class DataGridSelectionChangingEventArgs : CancelRoutedEventArgs + { + internal DataGridSelectionChangingEventArgs( IList selectionInfos, bool isCancelable ) + : base( DataGridControl.SelectionChangingEvent ) + { + this.SelectionInfos = selectionInfos; + this.IsCancelable = isCancelable; + } + + public bool IsCancelable + { + get; + private set; + } + + public IList SelectionInfos + { + get; + private set; + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DeletingSelectedItemErrorRoutedEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DeletingSelectedItemErrorRoutedEvent.cs similarity index 92% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DeletingSelectedItemErrorRoutedEventArgs.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DeletingSelectedItemErrorRoutedEvent.cs index db57f500..ce6f8975 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DeletingSelectedItemErrorRoutedEventArgs.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DeletingSelectedItemErrorRoutedEvent.cs @@ -1,102 +1,99 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - public delegate void DeletingSelectedItemErrorRoutedEventHandler( object sender, DeletingSelectedItemErrorRoutedEventArgs e ); - - public class DeletingSelectedItemErrorRoutedEventArgs : RoutedEventArgs - { - #region CONSTRUCTORS - - public DeletingSelectedItemErrorRoutedEventArgs( object item, Exception exception ) - : base() - { - m_item = item; - m_exception = exception; - } - - public DeletingSelectedItemErrorRoutedEventArgs( object item, Exception exception, RoutedEvent routedEvent ) - : base( routedEvent ) - { - m_item = item; - m_exception = exception; - } - - public DeletingSelectedItemErrorRoutedEventArgs( object item, Exception exception, RoutedEvent routedEvent, object source ) - : base( routedEvent, source ) - { - m_item = item; - m_exception = exception; - } - - #endregion CONSTRUCTORS - - #region Item Property - - public object Item - { - get - { - return m_item; - } - } - - #endregion Item Property - - #region Exception Property - - public Exception Exception - { - get - { - return m_exception; - } - } - - #endregion Exception Property - - #region Action Property - - public DeletingSelectedItemErrorAction Action - { - get - { - return m_action; - } - set - { - m_action = value; - } - } - - #endregion Action Property - - #region PRIVATE FIELDS - - private object m_item; - private Exception m_exception; - private DeletingSelectedItemErrorAction m_action = DeletingSelectedItemErrorAction.Skip; - - #endregion PRIVATE FIELDS - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + public delegate void DeletingSelectedItemErrorRoutedEventHandler( object sender, DeletingSelectedItemErrorRoutedEventArgs e ); + + public class DeletingSelectedItemErrorRoutedEventArgs : RoutedEventArgs + { + #region CONSTRUCTORS + + public DeletingSelectedItemErrorRoutedEventArgs( object item, Exception exception ) + : base() + { + m_item = item; + m_exception = exception; + } + + public DeletingSelectedItemErrorRoutedEventArgs( object item, Exception exception, RoutedEvent routedEvent ) + : base( routedEvent ) + { + m_item = item; + m_exception = exception; + } + + public DeletingSelectedItemErrorRoutedEventArgs( object item, Exception exception, RoutedEvent routedEvent, object source ) + : base( routedEvent, source ) + { + m_item = item; + m_exception = exception; + } + + #endregion CONSTRUCTORS + + #region Item Property + + public object Item + { + get + { + return m_item; + } + } + + #endregion Item Property + + #region Exception Property + + public Exception Exception + { + get + { + return m_exception; + } + } + + #endregion Exception Property + + #region Action Property + + public DeletingSelectedItemErrorAction Action + { + get + { + return m_action; + } + set + { + m_action = value; + } + } + + #endregion Action Property + + #region PRIVATE FIELDS + + private object m_item; + private Exception m_exception; + private DeletingSelectedItemErrorAction m_action = DeletingSelectedItemErrorAction.Skip; + + #endregion PRIVATE FIELDS + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DetailVisibilityChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DetailVisibilityChangedEventManager.cs similarity index 87% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DetailVisibilityChangedEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DetailVisibilityChangedEventManager.cs index de159e5a..336162ef 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DetailVisibilityChangedEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DetailVisibilityChangedEventManager.cs @@ -1,96 +1,89 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class DetailVisibilityChangedEventManager : WeakEventManager - { - private DetailVisibilityChangedEventManager() - { - } - - public static void AddListener( object source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( object source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - DetailConfiguration detailConfig = source as DetailConfiguration; - if( detailConfig != null ) - { - detailConfig.VisibilityChanged += new EventHandler( this.OnVisibilityChanged ); - return; - } - - DetailConfigurationCollection detailConfigCollection = source as DetailConfigurationCollection; - if( detailConfigCollection != null ) - { - detailConfigCollection.DetailVisibilityChanged += new EventHandler( this.OnVisibilityChanged ); - } - - } - - protected override void StopListening( object source ) - { - DetailConfiguration detailConfig = source as DetailConfiguration; - if( detailConfig != null ) - { - detailConfig.VisibilityChanged -= new EventHandler( this.OnVisibilityChanged ); - return; - } - - DetailConfigurationCollection detailConfigCollection = source as DetailConfigurationCollection; - if( detailConfigCollection != null ) - { - detailConfigCollection.DetailVisibilityChanged -= new EventHandler( this.OnVisibilityChanged ); - } - } - - private static DetailVisibilityChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( DetailVisibilityChangedEventManager ); - DetailVisibilityChangedEventManager currentManager = ( DetailVisibilityChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new DetailVisibilityChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnVisibilityChanged( object sender, EventArgs e ) - { - this.DeliverEvent( sender, e ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class DetailVisibilityChangedEventManager : WeakEventManager + { + internal static void AddListener( object source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( object source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + DetailConfiguration detailConfig = source as DetailConfiguration; + if( detailConfig != null ) + { + detailConfig.VisibilityChanged += new EventHandler( this.OnVisibilityChanged ); + return; + } + + DetailConfigurationCollection detailConfigCollection = source as DetailConfigurationCollection; + if( detailConfigCollection != null ) + { + detailConfigCollection.DetailVisibilityChanged += new EventHandler( this.OnVisibilityChanged ); + } + + } + + protected override void StopListening( object source ) + { + DetailConfiguration detailConfig = source as DetailConfiguration; + if( detailConfig != null ) + { + detailConfig.VisibilityChanged -= new EventHandler( this.OnVisibilityChanged ); + return; + } + + DetailConfigurationCollection detailConfigCollection = source as DetailConfigurationCollection; + if( detailConfigCollection != null ) + { + detailConfigCollection.DetailVisibilityChanged -= new EventHandler( this.OnVisibilityChanged ); + } + } + + private static DetailVisibilityChangedEventManager CurrentManager + { + get + { + Type managerType = typeof( DetailVisibilityChangedEventManager ); + DetailVisibilityChangedEventManager currentManager = ( DetailVisibilityChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new DetailVisibilityChangedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnVisibilityChanged( object sender, EventArgs e ) + { + this.DeliverEvent( sender, e ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DetailsChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DetailsChangedEventManager.cs similarity index 88% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DetailsChangedEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DetailsChangedEventManager.cs index 958a9c6a..aa10bd11 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DetailsChangedEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DetailsChangedEventManager.cs @@ -1,104 +1,98 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class DetailsChangedEventManager : WeakEventManager - { - private DetailsChangedEventManager() - { - } - - public static void AddListener( object source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( object source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - DataGridControl dataGridControl = source as DataGridControl; - if( dataGridControl != null ) - { - dataGridControl.DetailsChanged += this.OnDetailsChanged; - return; - } - else - { - CustomItemContainerGenerator generator = source as CustomItemContainerGenerator; - if( generator != null ) - { - generator.DetailsChanged += this.OnDetailsChanged; - return; - } - } - - throw new InvalidOperationException( "An attempt was made to use a source other than a DataGridControl or CustomItemContainerGenerator." ); - } - - protected override void StopListening( object source ) - { - DataGridControl dataGridControl = source as DataGridControl; - if( dataGridControl != null ) - { - dataGridControl.DetailsChanged -= this.OnDetailsChanged; - return; - } - else - { - CustomItemContainerGenerator generator = source as CustomItemContainerGenerator; - if( generator != null ) - { - generator.DetailsChanged -= this.OnDetailsChanged; - return; - } - } - - throw new InvalidOperationException( "An attempt was made to use a source other than a DataGridControl or CustomItemContainerGenerator." ); - } - - private static DetailsChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( DetailsChangedEventManager ); - DetailsChangedEventManager currentManager = ( DetailsChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new DetailsChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnDetailsChanged( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class DetailsChangedEventManager : WeakEventManager + { + internal static void AddListener( object source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( object source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + DataGridControl dataGridControl = source as DataGridControl; + if( dataGridControl != null ) + { + dataGridControl.DetailsChanged += this.OnDetailsChanged; + return; + } + else + { + CustomItemContainerGenerator generator = source as CustomItemContainerGenerator; + if( generator != null ) + { + generator.DetailsChanged += this.OnDetailsChanged; + return; + } + } + + throw new InvalidOperationException( "An attempt was made to use a source other than a DataGridControl or CustomItemContainerGenerator." ); + } + + protected override void StopListening( object source ) + { + DataGridControl dataGridControl = source as DataGridControl; + if( dataGridControl != null ) + { + dataGridControl.DetailsChanged -= this.OnDetailsChanged; + return; + } + else + { + CustomItemContainerGenerator generator = source as CustomItemContainerGenerator; + if( generator != null ) + { + generator.DetailsChanged -= this.OnDetailsChanged; + return; + } + } + + throw new InvalidOperationException( "An attempt was made to use a source other than a DataGridControl or CustomItemContainerGenerator." ); + } + + private static DetailsChangedEventManager CurrentManager + { + get + { + Type managerType = typeof( DetailsChangedEventManager ); + DetailsChangedEventManager currentManager = ( DetailsChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new DetailsChangedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnDetailsChanged( object sender, EventArgs args ) + { + this.DeliverEvent( sender, args ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DetailsExpansionChangedEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DetailsExpansionChangedEventArgs.cs new file mode 100644 index 00000000..3a5a9618 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DetailsExpansionChangedEventArgs.cs @@ -0,0 +1,63 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + public delegate void DetailsExpansionChangedEventHandler( object sender, DetailsExpansionChangedEventArgs e ); + + public class DetailsExpansionChangedEventArgs : RoutedEventArgs + { + public DetailsExpansionChangedEventArgs( RoutedEvent routedEvent, object dataItem, DataGridContext dataGridContext, bool isExpanded ) + : base( routedEvent ) + { + this.DataGridContext = dataGridContext; + this.IsExpanded = isExpanded; + this.MasterItem = dataItem; + } + + #region DataGridContext Property + + public DataGridContext DataGridContext + { + get; + private set; + } + + #endregion + + #region IsExpanded Property + + public bool IsExpanded + { + get; + private set; + } + + #endregion + + #region MasterItem Property + + public object MasterItem + { + get; + private set; + } + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DetailsExpansionChangingEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DetailsExpansionChangingEventArgs.cs new file mode 100644 index 00000000..b79426a0 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DetailsExpansionChangingEventArgs.cs @@ -0,0 +1,73 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + public delegate void DetailsExpansionChangingEventHandler( object sender, DetailsExpansionChangingEventArgs e ); + + public class DetailsExpansionChangingEventArgs : RoutedEventArgs + { + public DetailsExpansionChangingEventArgs( RoutedEvent routedEvent, object dataItem, DataGridContext dataGridContext, bool isExpanding ) + : base( routedEvent ) + { + this.DataGridContext = dataGridContext; + this.IsExpanding = isExpanding; + this.MasterItem = dataItem; + } + + #region Cancel Property + + public bool Cancel + { + get; + set; + } + + #endregion + + #region DataGridContext Property + + public DataGridContext DataGridContext + { + get; + private set; + } + + #endregion + + #region IsExpanding Property + + public bool IsExpanding + { + get; + private set; + } + + #endregion + + #region MasterItem Property + + public object MasterItem + { + get; + private set; + } + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/DistinctValuesRequestedEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DistinctValuesRequestedEvent.cs similarity index 80% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/DistinctValuesRequestedEventArgs.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DistinctValuesRequestedEvent.cs index 79139bcd..d0609a22 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/DistinctValuesRequestedEventArgs.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DistinctValuesRequestedEvent.cs @@ -1,53 +1,50 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; -using Xceed.Utils.Collections; -using System.Collections; - -namespace Xceed.Wpf.DataGrid -{ - internal class DistinctValuesRequestedEventArgs : EventArgs - { - public DistinctValuesRequestedEventArgs( string autoFilterColumnFieldName ) - { - m_autoFilterColumnFieldName = autoFilterColumnFieldName; - } - - public string AutoFilterColumnFieldName - { - get - { - return m_autoFilterColumnFieldName; - } - } - - public HashSet DistinctValues - { - get - { - return m_distinctValues; - } - } - - private string m_autoFilterColumnFieldName; - private HashSet m_distinctValues = new HashSet(); - } - - internal delegate void DistinctValuesRequestedEventHandler( object sender, DistinctValuesRequestedEventArgs e ); -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; + +namespace Xceed.Wpf.DataGrid +{ + internal class DistinctValuesRequestedEventArgs : EventArgs + { + internal DistinctValuesRequestedEventArgs( string autoFilterColumnFieldName ) + { + m_autoFilterColumnFieldName = autoFilterColumnFieldName; + } + + internal string AutoFilterColumnFieldName + { + get + { + return m_autoFilterColumnFieldName; + } + } + + internal HashSet DistinctValues + { + get + { + return m_distinctValues; + } + } + + private string m_autoFilterColumnFieldName; + private HashSet m_distinctValues = new HashSet(); + } + + internal delegate void DistinctValuesRequestedEventHandler( object sender, DistinctValuesRequestedEventArgs e ); +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/DistinctValuesRequestedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DistinctValuesRequestedEventManager.cs similarity index 84% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/DistinctValuesRequestedEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DistinctValuesRequestedEventManager.cs index f0b59f00..2f0e026b 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/DistinctValuesRequestedEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/DistinctValuesRequestedEventManager.cs @@ -1,74 +1,68 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class DistinctValuesRequestedEventManager: WeakEventManager - { - private DistinctValuesRequestedEventManager() - { - } - - public static void AddListener( ColumnCollection source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( ColumnCollection source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - ColumnCollection columns = ( ColumnCollection )source; - columns.DistinctValuesRequested += this.OnDistinctValuesRequested; - } - - protected override void StopListening( object source ) - { - ColumnCollection columns = ( ColumnCollection )source; - columns.DistinctValuesRequested -= this.OnDistinctValuesRequested; - } - - private static DistinctValuesRequestedEventManager CurrentManager - { - get - { - Type managerType = typeof( DistinctValuesRequestedEventManager ); - DistinctValuesRequestedEventManager currentManager = ( DistinctValuesRequestedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new DistinctValuesRequestedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnDistinctValuesRequested( object sender, DistinctValuesRequestedEventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class DistinctValuesRequestedEventManager: WeakEventManager + { + internal static void AddListener( ColumnCollection source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( ColumnCollection source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + ColumnCollection columns = ( ColumnCollection )source; + columns.DistinctValuesRequested += this.OnDistinctValuesRequested; + } + + protected override void StopListening( object source ) + { + ColumnCollection columns = ( ColumnCollection )source; + columns.DistinctValuesRequested -= this.OnDistinctValuesRequested; + } + + private static DistinctValuesRequestedEventManager CurrentManager + { + get + { + Type managerType = typeof( DistinctValuesRequestedEventManager ); + DistinctValuesRequestedEventManager currentManager = ( DistinctValuesRequestedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new DistinctValuesRequestedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnDistinctValuesRequested( object sender, DistinctValuesRequestedEventArgs args ) + { + this.DeliverEvent( sender, args ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FittedWidthRequestedEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/FittedWidthRequestedEvent.cs similarity index 96% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FittedWidthRequestedEventArgs.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/FittedWidthRequestedEvent.cs index 7a0843c0..359e8dd6 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FittedWidthRequestedEventArgs.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/FittedWidthRequestedEvent.cs @@ -1,51 +1,51 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; - -namespace Xceed.Wpf.DataGrid -{ - internal sealed class FittedWidthRequestedEventArgs : EventArgs - { - #region Value Internal Read-Only Property - - internal Nullable Value - { - get - { - return m_value; - } - } - - internal void SetValue( double value ) - { - if( m_value.HasValue ) - { - // We keep the highest of the two values. - if( m_value.Value >= value ) - return; - } - - m_value = value; - } - - private Nullable m_value; - - #endregion - } - - internal delegate void FittedWidthRequestedEventHandler( object sender, FittedWidthRequestedEventArgs e ); -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; + +namespace Xceed.Wpf.DataGrid +{ + internal sealed class FittedWidthRequestedEventArgs : EventArgs + { + #region Value Internal Read-Only Property + + internal Nullable Value + { + get + { + return m_value; + } + } + + internal void SetValue( double value ) + { + if( m_value.HasValue ) + { + // We keep the highest of the two values. + if( m_value.Value >= value ) + return; + } + + m_value = value; + } + + private Nullable m_value; + + #endregion + } + + internal delegate void FittedWidthRequestedEventHandler( object sender, FittedWidthRequestedEventArgs e ); +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/FrameworkElementUnloadedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/FrameworkElementUnloadedEventManager.cs new file mode 100644 index 00000000..664a7244 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/FrameworkElementUnloadedEventManager.cs @@ -0,0 +1,88 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; +using System.Windows.Threading; + +namespace Xceed.Wpf.DataGrid +{ + internal sealed class FrameworkElementUnloadedEventManager : WeakEventManager + { + internal static void AddListener( FrameworkElement source, IWeakEventListener listener ) + { + FrameworkElementUnloadedEventManager.CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( FrameworkElement source, IWeakEventListener listener ) + { + FrameworkElementUnloadedEventManager.CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + var fe = source as FrameworkElement; + if( fe == null ) + return; + + fe.Unloaded += new RoutedEventHandler( this.OnEventRaised ); + } + + protected override void StopListening( object source ) + { + var fe = source as FrameworkElement; + if( fe == null ) + return; + + var dispatcher = fe.Dispatcher; + if( dispatcher.CheckAccess() ) + { + this.StopListening( fe ); + } + else + { + dispatcher.BeginInvoke( new Action( this.StopListening ), DispatcherPriority.Send, fe ); + } + } + + private static FrameworkElementUnloadedEventManager CurrentManager + { + get + { + var managerType = typeof( FrameworkElementUnloadedEventManager ); + var currentManager = ( FrameworkElementUnloadedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new FrameworkElementUnloadedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void StopListening( FrameworkElement fe ) + { + fe.Unloaded -= new RoutedEventHandler( this.OnEventRaised ); + } + + private void OnEventRaised( object sender, RoutedEventArgs e ) + { + this.DeliverEvent( sender, e ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/GroupConfigurationSelectorChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/GroupConfigurationSelectorChangedEventManager.cs similarity index 90% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/GroupConfigurationSelectorChangedEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/GroupConfigurationSelectorChangedEventManager.cs index 91f38f28..4e7de696 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/GroupConfigurationSelectorChangedEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/GroupConfigurationSelectorChangedEventManager.cs @@ -1,116 +1,110 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class GroupConfigurationSelectorChangedEventManager : WeakEventManager - { - private GroupConfigurationSelectorChangedEventManager() - { - } - - public static void AddListener( object source, IWeakEventListener listener) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( object source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - DataGridContext context = source as DataGridContext; - - if (context != null) - { - context.GroupConfigurationSelectorChanged += new EventHandler(this.OnGroupConfigurationSelectorChanged); - return; - } - - DataGridControl dataGridControl = source as DataGridControl; - if (dataGridControl != null) - { - dataGridControl.GroupConfigurationSelectorChanged += new EventHandler(this.OnGroupConfigurationSelectorChanged); - return; - } - - DetailConfiguration detailConfig = source as DetailConfiguration; - if (detailConfig != null) - { - detailConfig.GroupConfigurationSelectorChanged += new EventHandler(this.OnGroupConfigurationSelectorChanged); - return; - } - - throw new InvalidOperationException("An attempt was made to register an item other than a DataGridContext, DataGridControl, or DetailConfiguration to the GroupConfigurationSelectorChangedEventManager."); - } - - protected override void StopListening(object source) - { - DataGridContext context = source as DataGridContext; - - if (context != null) - { - context.GroupConfigurationSelectorChanged -= new EventHandler(this.OnGroupConfigurationSelectorChanged); - return; - } - - DataGridControl dataGridControl = source as DataGridControl; - if (dataGridControl != null) - { - dataGridControl.GroupConfigurationSelectorChanged -= new EventHandler(this.OnGroupConfigurationSelectorChanged); - return; - } - - DetailConfiguration detailConfig = source as DetailConfiguration; - if (detailConfig != null) - { - detailConfig.GroupConfigurationSelectorChanged -= new EventHandler(this.OnGroupConfigurationSelectorChanged); - return; - } - - throw new InvalidOperationException( "An attempt was made to unregister an item other than a DataGridContext, DataGridControl, or DetailConfiguration from the GroupConfigurationSelectorChangedEventManager." ); - } - - private static GroupConfigurationSelectorChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( GroupConfigurationSelectorChangedEventManager ); - GroupConfigurationSelectorChangedEventManager currentManager = ( GroupConfigurationSelectorChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new GroupConfigurationSelectorChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnGroupConfigurationSelectorChanged( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class GroupConfigurationSelectorChangedEventManager : WeakEventManager + { + internal static void AddListener( object source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( object source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + DataGridContext context = source as DataGridContext; + + if (context != null) + { + context.GroupConfigurationSelectorChanged += new EventHandler(this.OnGroupConfigurationSelectorChanged); + return; + } + + DataGridControl dataGridControl = source as DataGridControl; + if (dataGridControl != null) + { + dataGridControl.GroupConfigurationSelectorChanged += new EventHandler(this.OnGroupConfigurationSelectorChanged); + return; + } + + DetailConfiguration detailConfig = source as DetailConfiguration; + if (detailConfig != null) + { + detailConfig.GroupConfigurationSelectorChanged += new EventHandler(this.OnGroupConfigurationSelectorChanged); + return; + } + + throw new InvalidOperationException("An attempt was made to register an item other than a DataGridContext, DataGridControl, or DetailConfiguration to the GroupConfigurationSelectorChangedEventManager."); + } + + protected override void StopListening(object source) + { + DataGridContext context = source as DataGridContext; + + if (context != null) + { + context.GroupConfigurationSelectorChanged -= new EventHandler(this.OnGroupConfigurationSelectorChanged); + return; + } + + DataGridControl dataGridControl = source as DataGridControl; + if (dataGridControl != null) + { + dataGridControl.GroupConfigurationSelectorChanged -= new EventHandler(this.OnGroupConfigurationSelectorChanged); + return; + } + + DetailConfiguration detailConfig = source as DetailConfiguration; + if (detailConfig != null) + { + detailConfig.GroupConfigurationSelectorChanged -= new EventHandler(this.OnGroupConfigurationSelectorChanged); + return; + } + + throw new InvalidOperationException( "An attempt was made to unregister an item other than a DataGridContext, DataGridControl, or DetailConfiguration from the GroupConfigurationSelectorChangedEventManager." ); + } + + private static GroupConfigurationSelectorChangedEventManager CurrentManager + { + get + { + Type managerType = typeof( GroupConfigurationSelectorChangedEventManager ); + GroupConfigurationSelectorChangedEventManager currentManager = ( GroupConfigurationSelectorChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new GroupConfigurationSelectorChangedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnGroupConfigurationSelectorChanged( object sender, EventArgs args ) + { + this.DeliverEvent( sender, args ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/GroupExpansionChangedEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/GroupExpansionChangedEventArgs.cs new file mode 100644 index 00000000..9cac5769 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/GroupExpansionChangedEventArgs.cs @@ -0,0 +1,75 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System.Windows; +using System.Windows.Data; + +namespace Xceed.Wpf.DataGrid +{ + public delegate void GroupExpansionChangedEventHandler( object sender, GroupExpansionChangedEventArgs e ); + + public class GroupExpansionChangedEventArgs : RoutedEventArgs + { + public GroupExpansionChangedEventArgs( RoutedEvent routedEvent, Group group, CollectionViewGroup collectionViewGroup, DataGridContext dataGridContext, bool isExpanded ) + : base( routedEvent ) + { + this.CollectionViewGroup = collectionViewGroup; + this.DataGridContext = dataGridContext; + this.Group = group; + this.IsExpanded = isExpanded; + } + + #region CollectionViewGroup Property + + public CollectionViewGroup CollectionViewGroup + { + get; + private set; + } + + #endregion + + #region DataGridContext Property + + public DataGridContext DataGridContext + { + get; + private set; + } + + #endregion + + #region Group Property + + public Group Group + { + get; + private set; + } + + #endregion + + #region IsExpanded Property + + public bool IsExpanded + { + get; + private set; + } + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/GroupExpansionChangingEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/GroupExpansionChangingEventArgs.cs new file mode 100644 index 00000000..bae3a76b --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/GroupExpansionChangingEventArgs.cs @@ -0,0 +1,85 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System.Windows; +using System.Windows.Data; + +namespace Xceed.Wpf.DataGrid +{ + public delegate void GroupExpansionChangingEventHandler( object sender, GroupExpansionChangingEventArgs e ); + + public class GroupExpansionChangingEventArgs : RoutedEventArgs + { + public GroupExpansionChangingEventArgs( RoutedEvent routedEvent, Group group, CollectionViewGroup collectionViewGroup, DataGridContext dataGridContext, bool isExpanding ) + : base( routedEvent ) + { + this.CollectionViewGroup = collectionViewGroup; + this.DataGridContext = dataGridContext; + this.Group = group; + this.IsExpanding = isExpanding; + } + + #region Cancel Property + + public bool Cancel + { + get; + set; + } + + #endregion + + #region CollectionViewGroup Property + + public CollectionViewGroup CollectionViewGroup + { + get; + private set; + } + + #endregion + + #region DataGridContext Property + + public DataGridContext DataGridContext + { + get; + private set; + } + + #endregion + + #region Group Property + + public Group Group + { + get; + private set; + } + + #endregion + + #region IsExpanding Property + + public bool IsExpanding + { + get; + private set; + } + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/VisibleColumnsUpdatedEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/InitializeItemPropertyEventArgs.cs similarity index 63% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/VisibleColumnsUpdatedEventArgs.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/InitializeItemPropertyEventArgs.cs index 2878b5bb..b9317115 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/VisibleColumnsUpdatedEventArgs.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/InitializeItemPropertyEventArgs.cs @@ -1,42 +1,41 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; - -namespace Xceed.Wpf.DataGrid -{ - internal class VisibleColumnsUpdatedEventArgs : EventArgs - { - internal VisibleColumnsUpdatedEventArgs( bool onlyIncrementFlag ) - { - m_onlyIncrementFlag = onlyIncrementFlag; - } - - #region OnlyIncrementFlag Property - - internal bool OnlyIncrementFlag - { - get - { - return m_onlyIncrementFlag; - } - } - - private bool m_onlyIncrementFlag; - - #endregion - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; + +namespace Xceed.Wpf.DataGrid +{ + internal class InitializeItemPropertyEventArgs : EventArgs + { + internal InitializeItemPropertyEventArgs( DataGridItemPropertyBase itemProperty ) + { + if( itemProperty == null ) + throw new ArgumentNullException( "itemProperty" ); + + m_itemProperty = itemProperty; + } + + internal DataGridItemPropertyBase ItemProperty + { + get + { + return m_itemProperty; + } + } + + private readonly DataGridItemPropertyBase m_itemProperty; + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/VisibilityChangingEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/InitializeItemPropertyEventManager.cs similarity index 51% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/VisibilityChangingEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/InitializeItemPropertyEventManager.cs index 819e8582..14145220 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/VisibilityChangingEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/InitializeItemPropertyEventManager.cs @@ -1,72 +1,68 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class VisibilityChangingEventManager : WeakEventManager - { - private VisibilityChangingEventManager() - { - } - - public static void AddListener( ColumnCollection source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( ColumnCollection source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - var columnCollection = ( ColumnCollection )source; - columnCollection.ColumnVisibilityChanging += new EventHandler( this.OnColumnVisibilityChanging ); - } - - protected override void StopListening( object source ) - { - var columnCollection = ( ColumnCollection )source; - columnCollection.ColumnVisibilityChanging -= new EventHandler( this.OnColumnVisibilityChanging ); - } - - private static VisibilityChangingEventManager CurrentManager - { - get - { - var managerType = typeof( VisibilityChangingEventManager ); - var currentManager = ( VisibilityChangingEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new VisibilityChangingEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnColumnVisibilityChanging( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal sealed class InitializeItemPropertyEventManager : WeakEventManager + { + internal static void AddListener( DataGridItemPropertyCollection source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( DataGridItemPropertyCollection source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + var target = ( DataGridItemPropertyCollection )source; + target.InitializeItemProperty += new EventHandler( this.OnEventRaised ); + } + + protected override void StopListening( object source ) + { + var target = ( DataGridItemPropertyCollection )source; + target.InitializeItemProperty -= new EventHandler( this.OnEventRaised ); + } + + private static InitializeItemPropertyEventManager CurrentManager + { + get + { + var managerType = typeof( InitializeItemPropertyEventManager ); + var currentManager = ( InitializeItemPropertyEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new InitializeItemPropertyEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnEventRaised( object sender, InitializeItemPropertyEventArgs e ) + { + this.DeliverEvent( sender, e ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ItemsSourceChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ItemsSourceChangedEventManager.cs similarity index 86% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ItemsSourceChangedEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ItemsSourceChangedEventManager.cs index 8bc403a4..a75070b8 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ItemsSourceChangedEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ItemsSourceChangedEventManager.cs @@ -1,72 +1,68 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class ItemsSourceChangeCompletedEventManager : WeakEventManager - { - private ItemsSourceChangeCompletedEventManager() - { - } - - public static void AddListener( DataGridControl source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( DataGridControl source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - DataGridControl dataGridControl = ( DataGridControl )source; - dataGridControl.ItemsSourceChangeCompleted += new EventHandler( this.OnItemsSourceChanged ); - } - - protected override void StopListening( object source ) - { - DataGridControl dataGridControl = ( DataGridControl )source; - dataGridControl.ItemsSourceChangeCompleted -= new EventHandler( this.OnItemsSourceChanged ); - } - - private static ItemsSourceChangeCompletedEventManager CurrentManager - { - get - { - Type managerType = typeof( ItemsSourceChangeCompletedEventManager ); - ItemsSourceChangeCompletedEventManager currentManager = ( ItemsSourceChangeCompletedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new ItemsSourceChangeCompletedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnItemsSourceChanged( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class ItemsSourceChangeCompletedEventManager : WeakEventManager + { + internal static void AddListener( DataGridControl source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( DataGridControl source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + DataGridControl dataGridControl = ( DataGridControl )source; + dataGridControl.ItemsSourceChangeCompleted += new EventHandler( this.OnItemsSourceChanged ); + } + + protected override void StopListening( object source ) + { + DataGridControl dataGridControl = ( DataGridControl )source; + dataGridControl.ItemsSourceChangeCompleted -= new EventHandler( this.OnItemsSourceChanged ); + } + + private static ItemsSourceChangeCompletedEventManager CurrentManager + { + get + { + Type managerType = typeof( ItemsSourceChangeCompletedEventManager ); + ItemsSourceChangeCompletedEventManager currentManager = ( ItemsSourceChangeCompletedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new ItemsSourceChangeCompletedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnItemsSourceChanged( object sender, EventArgs args ) + { + this.DeliverEvent( sender, args ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Utils/Collections/ListChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ListChangedEventManager.cs similarity index 83% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Utils/Collections/ListChangedEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ListChangedEventManager.cs index 52c20ba2..77528b36 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Utils/Collections/ListChangedEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ListChangedEventManager.cs @@ -1,75 +1,69 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows; -using System.ComponentModel; - -namespace Xceed.Utils.Collections -{ - internal class ListChangedEventManager : WeakEventManager - { - private ListChangedEventManager() - { - } - - public static void AddListener( IBindingList source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( IBindingList source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - IBindingList list = ( IBindingList )source; - list.ListChanged += new ListChangedEventHandler( this.OnListChanged ); - } - - protected override void StopListening( object source ) - { - IBindingList list = ( IBindingList )source; - list.ListChanged -= new ListChangedEventHandler( this.OnListChanged ); - } - - private static ListChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( ListChangedEventManager ); - ListChangedEventManager currentManager = ( ListChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new ListChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnListChanged( object sender, ListChangedEventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.ComponentModel; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class ListChangedEventManager : WeakEventManager + { + internal static void AddListener( IBindingList source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( IBindingList source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + IBindingList list = ( IBindingList )source; + list.ListChanged += new ListChangedEventHandler( this.OnListChanged ); + } + + protected override void StopListening( object source ) + { + IBindingList list = ( IBindingList )source; + list.ListChanged -= new ListChangedEventHandler( this.OnListChanged ); + } + + private static ListChangedEventManager CurrentManager + { + get + { + Type managerType = typeof( ListChangedEventManager ); + ListChangedEventManager currentManager = ( ListChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new ListChangedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnListChanged( object sender, ListChangedEventArgs args ) + { + this.DeliverEvent( sender, args ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/MappingChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/MappingChangedEventManager.cs new file mode 100644 index 00000000..9abbaea8 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/MappingChangedEventManager.cs @@ -0,0 +1,66 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal sealed class MappingChangedEventManager : WeakEventManager + { + internal static void AddListener( DataGridItemPropertyMap source, IWeakEventListener listener ) + { + MappingChangedEventManager.CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( DataGridItemPropertyMap source, IWeakEventListener listener ) + { + MappingChangedEventManager.CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + ( ( DataGridItemPropertyMap )source ).MappingChanged += new EventHandler( this.OnEventRaised ); + } + + protected override void StopListening( object source ) + { + ( ( DataGridItemPropertyMap )source ).MappingChanged -= new EventHandler( this.OnEventRaised ); + } + + private static MappingChangedEventManager CurrentManager + { + get + { + var managerType = typeof( MappingChangedEventManager ); + var currentManager = ( MappingChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new MappingChangedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnEventRaised( object sender, EventArgs e ) + { + this.DeliverEvent( sender, e ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/MaxGroupLevelsChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/MaxGroupLevelsChangedEventManager.cs similarity index 88% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/MaxGroupLevelsChangedEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/MaxGroupLevelsChangedEventManager.cs index cfe94f64..4274cbe0 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/MaxGroupLevelsChangedEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/MaxGroupLevelsChangedEventManager.cs @@ -1,100 +1,94 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class MaxGroupLevelsChangedEventManager : WeakEventManager - { - private MaxGroupLevelsChangedEventManager() - { - } - - public static void AddListener( object source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( object source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - DataGridControl dataGridControl = source as DataGridControl; - if( dataGridControl != null ) - { - dataGridControl.MaxGroupLevelsChanged += new EventHandler( this.OnMaxGroupLevelsChanged ); - return; - } - - DetailConfiguration detailConfiguration = source as DetailConfiguration; - if( detailConfiguration != null ) - { - detailConfiguration.MaxGroupLevelsChanged += new EventHandler( this.OnMaxGroupLevelsChanged ); - return; - } - - throw new ArgumentException( "The specified source must be a DataGridControl or a DetailConfiguration.", "source" ); - } - - protected override void StopListening( object source ) - { - DataGridControl dataGridControl = source as DataGridControl; - if( dataGridControl != null ) - { - dataGridControl.MaxGroupLevelsChanged -= new EventHandler( this.OnMaxGroupLevelsChanged ); - return; - } - - DetailConfiguration detailConfiguration = source as DetailConfiguration; - if( detailConfiguration != null ) - { - detailConfiguration.MaxGroupLevelsChanged -= new EventHandler( this.OnMaxGroupLevelsChanged ); - return; - } - - throw new ArgumentException( "The specified source must be a DataGridControl or a DetailConfiguration.", "source" ); - } - - private static MaxGroupLevelsChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( MaxGroupLevelsChangedEventManager ); - MaxGroupLevelsChangedEventManager currentManager = ( MaxGroupLevelsChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new MaxGroupLevelsChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnMaxGroupLevelsChanged( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class MaxGroupLevelsChangedEventManager : WeakEventManager + { + internal static void AddListener( object source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( object source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + DataGridControl dataGridControl = source as DataGridControl; + if( dataGridControl != null ) + { + dataGridControl.MaxGroupLevelsChanged += new EventHandler( this.OnMaxGroupLevelsChanged ); + return; + } + + DetailConfiguration detailConfiguration = source as DetailConfiguration; + if( detailConfiguration != null ) + { + detailConfiguration.MaxGroupLevelsChanged += new EventHandler( this.OnMaxGroupLevelsChanged ); + return; + } + + throw new ArgumentException( "The specified source must be a DataGridControl or a DetailConfiguration.", "source" ); + } + + protected override void StopListening( object source ) + { + DataGridControl dataGridControl = source as DataGridControl; + if( dataGridControl != null ) + { + dataGridControl.MaxGroupLevelsChanged -= new EventHandler( this.OnMaxGroupLevelsChanged ); + return; + } + + DetailConfiguration detailConfiguration = source as DetailConfiguration; + if( detailConfiguration != null ) + { + detailConfiguration.MaxGroupLevelsChanged -= new EventHandler( this.OnMaxGroupLevelsChanged ); + return; + } + + throw new ArgumentException( "The specified source must be a DataGridControl or a DetailConfiguration.", "source" ); + } + + private static MaxGroupLevelsChangedEventManager CurrentManager + { + get + { + Type managerType = typeof( MaxGroupLevelsChangedEventManager ); + MaxGroupLevelsChangedEventManager currentManager = ( MaxGroupLevelsChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new MaxGroupLevelsChangedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnMaxGroupLevelsChanged( object sender, EventArgs args ) + { + this.DeliverEvent( sender, args ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/MaxSortLevelsChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/MaxSortLevelsChangedEventManager.cs similarity index 88% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/MaxSortLevelsChangedEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/MaxSortLevelsChangedEventManager.cs index edc9fe8b..d6bf7273 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/MaxSortLevelsChangedEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/MaxSortLevelsChangedEventManager.cs @@ -1,100 +1,94 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class MaxSortLevelsChangedEventManager : WeakEventManager - { - private MaxSortLevelsChangedEventManager() - { - } - - public static void AddListener( object source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( object source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - DataGridControl dataGridControl = source as DataGridControl; - if( dataGridControl != null ) - { - dataGridControl.MaxSortLevelsChanged += new EventHandler( this.OnMaxSortLevelsChanged ); - return; - } - - DetailConfiguration detailConfiguration = source as DetailConfiguration; - if( detailConfiguration != null ) - { - detailConfiguration.MaxSortLevelsChanged += new EventHandler( this.OnMaxSortLevelsChanged ); - return; - } - - throw new ArgumentException( "The specified source must be a DataGridControl or a DetailConfiguration.", "source" ); - } - - protected override void StopListening( object source ) - { - DataGridControl dataGridControl = source as DataGridControl; - if( dataGridControl != null ) - { - dataGridControl.MaxSortLevelsChanged -= new EventHandler( this.OnMaxSortLevelsChanged ); - return; - } - - DetailConfiguration detailConfiguration = source as DetailConfiguration; - if( detailConfiguration != null ) - { - detailConfiguration.MaxSortLevelsChanged -= new EventHandler( this.OnMaxSortLevelsChanged ); - return; - } - - throw new ArgumentException( "The specified source must be a DataGridControl or a DetailConfiguration.", "source" ); - } - - private static MaxSortLevelsChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( MaxSortLevelsChangedEventManager ); - MaxSortLevelsChangedEventManager currentManager = ( MaxSortLevelsChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new MaxSortLevelsChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnMaxSortLevelsChanged( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class MaxSortLevelsChangedEventManager : WeakEventManager + { + internal static void AddListener( object source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( object source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + DataGridControl dataGridControl = source as DataGridControl; + if( dataGridControl != null ) + { + dataGridControl.MaxSortLevelsChanged += new EventHandler( this.OnMaxSortLevelsChanged ); + return; + } + + DetailConfiguration detailConfiguration = source as DetailConfiguration; + if( detailConfiguration != null ) + { + detailConfiguration.MaxSortLevelsChanged += new EventHandler( this.OnMaxSortLevelsChanged ); + return; + } + + throw new ArgumentException( "The specified source must be a DataGridControl or a DetailConfiguration.", "source" ); + } + + protected override void StopListening( object source ) + { + DataGridControl dataGridControl = source as DataGridControl; + if( dataGridControl != null ) + { + dataGridControl.MaxSortLevelsChanged -= new EventHandler( this.OnMaxSortLevelsChanged ); + return; + } + + DetailConfiguration detailConfiguration = source as DetailConfiguration; + if( detailConfiguration != null ) + { + detailConfiguration.MaxSortLevelsChanged -= new EventHandler( this.OnMaxSortLevelsChanged ); + return; + } + + throw new ArgumentException( "The specified source must be a DataGridControl or a DetailConfiguration.", "source" ); + } + + private static MaxSortLevelsChangedEventManager CurrentManager + { + get + { + Type managerType = typeof( MaxSortLevelsChangedEventManager ); + MaxSortLevelsChangedEventManager currentManager = ( MaxSortLevelsChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new MaxSortLevelsChangedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnMaxSortLevelsChanged( object sender, EventArgs args ) + { + this.DeliverEvent( sender, args ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/NotifyBatchCollectionChangedEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/NotifyBatchCollectionChangedEventArgs.cs new file mode 100644 index 00000000..43066596 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/NotifyBatchCollectionChangedEventArgs.cs @@ -0,0 +1,349 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Diagnostics; + +namespace Xceed.Wpf.DataGrid +{ + internal sealed class NotifyBatchCollectionChangedEventArgs : NotifyCollectionChangedEventArgs + { + private NotifyBatchCollectionChangedEventArgs( NotifyCollectionChangedAction action ) + : base( action ) + { + } + + private NotifyBatchCollectionChangedEventArgs( NotifyCollectionChangedAction action, IList changedItems ) + : base( action, changedItems ) + { + } + + private NotifyBatchCollectionChangedEventArgs( NotifyCollectionChangedAction action, IList changedItems, int startingIndex ) + : base( action, changedItems, startingIndex ) + { + } + + private NotifyBatchCollectionChangedEventArgs( NotifyCollectionChangedAction action, IList changedItems, int index, int oldIndex ) + : base( action, changedItems, index, oldIndex ) + { + } + + private NotifyBatchCollectionChangedEventArgs( NotifyCollectionChangedAction action, IList newItems, IList oldItems ) + : base( action, newItems, oldItems ) + { + } + + private NotifyBatchCollectionChangedEventArgs( NotifyCollectionChangedAction action, IList newItems, IList oldItems, int startingIndex ) + : base( action, newItems, oldItems, startingIndex ) + { + } + + #region Replacements Property + + internal IDictionary Replacements + { + get + { + if( m_fromTo == null ) + { + m_fromTo = new Dictionary( 0 ); + m_toFrom = new Dictionary( 0 ); + } + + return m_fromTo; + } + } + + #endregion + + internal static NotifyBatchCollectionChangedEventArgs Combine( NotifyCollectionChangedEventArgs x, NotifyCollectionChangedEventArgs y ) + { + return NotifyBatchCollectionChangedEventArgs.Combine( + NotifyBatchCollectionChangedEventArgs.Create( x ), + NotifyBatchCollectionChangedEventArgs.Create( y ) ); + } + + private static NotifyBatchCollectionChangedEventArgs Combine( NotifyBatchCollectionChangedEventArgs x, NotifyBatchCollectionChangedEventArgs y ) + { + if( x == null ) + return y; + + if( y == null ) + return x; + + var replacements = default( BiMap ); + var result = default( NotifyBatchCollectionChangedEventArgs ); + + if( x.Action == y.Action ) + { + switch( x.Action ) + { + case NotifyCollectionChangedAction.Replace: + { + replacements = NotifyBatchCollectionChangedEventArgs.Merge( + NotifyBatchCollectionChangedEventArgs.Map( x.OldItems, x.NewItems ), + NotifyBatchCollectionChangedEventArgs.Map( y.OldItems, y.NewItems ) ); + if( replacements == null ) + return null; + + result = new NotifyBatchCollectionChangedEventArgs( NotifyCollectionChangedAction.Reset ); + } + break; + + case NotifyCollectionChangedAction.Add: + case NotifyCollectionChangedAction.Remove: + case NotifyCollectionChangedAction.Move: + result = new NotifyBatchCollectionChangedEventArgs( NotifyCollectionChangedAction.Reset ); + break; + + case NotifyCollectionChangedAction.Reset: + result = new NotifyBatchCollectionChangedEventArgs( NotifyCollectionChangedAction.Reset ); + replacements = NotifyBatchCollectionChangedEventArgs.Merge( x.m_fromTo, y.m_fromTo ); + break; + + default: + throw new NotSupportedException(); + } + } + else + { + if( x.Action == NotifyCollectionChangedAction.Replace ) + { + replacements = NotifyBatchCollectionChangedEventArgs.Merge( NotifyBatchCollectionChangedEventArgs.Map( x.OldItems, x.NewItems ), null ); + } + else if( ( x.Action == NotifyCollectionChangedAction.Reset ) && ( x.m_fromTo != null ) ) + { + replacements = new BiMap( x.m_fromTo, x.m_toFrom ); + } + + switch( y.Action ) + { + case NotifyCollectionChangedAction.Add: + { + if( replacements != null ) + { + var fromTo = replacements.FromTo; + var toFrom = replacements.ToFrom; + + foreach( var item in y.NewItems ) + { + object to; + + if( fromTo.TryGetValue( item, out to ) ) + { + fromTo.Remove( item ); + toFrom.Remove( to ); + } + } + } + } + break; + + case NotifyCollectionChangedAction.Remove: + { + if( replacements != null ) + { + var fromTo = replacements.FromTo; + var toFrom = replacements.ToFrom; + + foreach( var item in y.OldItems ) + { + object from; + + if( toFrom.TryGetValue( item, out from ) ) + { + fromTo.Remove( from ); + toFrom.Remove( item ); + } + } + } + } + break; + + case NotifyCollectionChangedAction.Replace: + { + var mapping = NotifyBatchCollectionChangedEventArgs.Map( y.OldItems, y.NewItems ); + + if( replacements != null ) + { + replacements = NotifyBatchCollectionChangedEventArgs.Merge( replacements.FromTo, mapping ); + } + else + { + replacements = NotifyBatchCollectionChangedEventArgs.Merge( mapping, null ); + } + } + break; + + case NotifyCollectionChangedAction.Move: + break; + + case NotifyCollectionChangedAction.Reset: + { + if( replacements != null ) + { + replacements = NotifyBatchCollectionChangedEventArgs.Merge( replacements.FromTo, y.m_fromTo ); + } + else + { + replacements = NotifyBatchCollectionChangedEventArgs.Merge( y.m_fromTo, null ); + } + } + break; + + default: + throw new NotSupportedException(); + } + + result = new NotifyBatchCollectionChangedEventArgs( NotifyCollectionChangedAction.Reset ); + } + + if( ( result != null ) && ( replacements != null ) ) + { + result.m_fromTo = replacements.FromTo; + result.m_toFrom = replacements.ToFrom; + } + + return result; + } + + private static NotifyBatchCollectionChangedEventArgs Create( NotifyCollectionChangedEventArgs e ) + { + if( e == null ) + return null; + + var batch = e as NotifyBatchCollectionChangedEventArgs; + if( batch != null ) + return batch; + + switch( e.Action ) + { + case NotifyCollectionChangedAction.Add: + return new NotifyBatchCollectionChangedEventArgs( e.Action, e.NewItems, e.NewStartingIndex ); + + case NotifyCollectionChangedAction.Remove: + return new NotifyBatchCollectionChangedEventArgs( e.Action, e.OldItems, e.OldStartingIndex ); + + case NotifyCollectionChangedAction.Move: + return new NotifyBatchCollectionChangedEventArgs( e.Action, e.OldItems, e.NewStartingIndex, e.OldStartingIndex ); + + case NotifyCollectionChangedAction.Replace: + return new NotifyBatchCollectionChangedEventArgs( e.Action, e.NewItems, e.OldItems, e.OldStartingIndex ); + + case NotifyCollectionChangedAction.Reset: + return new NotifyBatchCollectionChangedEventArgs( e.Action ); + + default: + throw new NotSupportedException(); + } + } + + private static BiMap Merge( IDictionary x, IDictionary y ) + { + var fromTo = new Dictionary(); + var toFrom = new Dictionary(); + + if( x != null ) + { + foreach( var entry in x ) + { + if( object.ReferenceEquals( entry.Key, entry.Value ) ) + continue; + + fromTo.Add( entry.Key, entry.Value ); + toFrom.Add( entry.Value, entry.Key ); + } + } + + if( y != null ) + { + foreach( var entry in y ) + { + if( object.ReferenceEquals( entry.Key, entry.Value ) ) + continue; + + // Keep only the initial and final value. For example, (A -> B -> C) becomes (A -> C). + var from = default( object ); + if( toFrom.TryGetValue( entry.Key, out from ) ) + { + toFrom.Remove( entry.Key ); + + if( object.ReferenceEquals( from, entry.Value ) ) + { + fromTo.Remove( from ); + } + else + { + fromTo[ from ] = entry.Value; + toFrom[ entry.Value ] = from; + } + } + else + { + // There is no need to check if the entry exists, since it should not or the same instance + // is use multiple time in the data source, which is not supported by the grid. + fromTo.Add( entry.Key, entry.Value ); + toFrom.Add( entry.Value, entry.Key ); + } + } + } + + if( fromTo.Count <= 0 ) + return null; + + return new BiMap( fromTo, toFrom ); + } + + private static IDictionary Map( IList oldItems, IList newItems ) + { + Debug.Assert( oldItems != null ); + Debug.Assert( newItems != null ); + Debug.Assert( oldItems.Count == newItems.Count ); + + var items = new Dictionary(); + var count = oldItems.Count; + + for( int i = 0; i < count; i++ ) + { + items.Add( oldItems[ i ], newItems[ i ] ); + } + + return items; + } + + private IDictionary m_fromTo; + private IDictionary m_toFrom; + + #region BiMap Private Class + + private sealed class BiMap + { + internal BiMap( IDictionary fromTo, IDictionary toFrom ) + { + this.FromTo = fromTo; + this.ToFrom = toFrom; + } + + internal readonly IDictionary FromTo; + internal readonly IDictionary ToFrom; + } + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/NotifyCollectionChangedEventArgsExtensions.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/NotifyCollectionChangedEventArgsExtensions.cs similarity index 55% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/NotifyCollectionChangedEventArgsExtensions.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/NotifyCollectionChangedEventArgsExtensions.cs index 26ee117f..8ac11222 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/NotifyCollectionChangedEventArgsExtensions.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/NotifyCollectionChangedEventArgsExtensions.cs @@ -1,36 +1,72 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Specialized; - -namespace Xceed.Wpf.DataGrid -{ - internal static class NotifyCollectionChangedEventArgsExtensions - { - internal static NotifyCollectionChangedEventArgs GetRangeActionOrSelf( this NotifyCollectionChangedEventArgs source ) - { - if( source == null ) - throw new ArgumentNullException( "source" ); - - var rangeEventArgs = source as NotifyRangeCollectionChangedEventArgs; - if( rangeEventArgs != null ) - return rangeEventArgs.OriginalEventArgs; - - return source; - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Specialized; + +namespace Xceed.Wpf.DataGrid +{ + internal static class NotifyCollectionChangedEventArgsExtensions + { + internal static NotifyCollectionChangedEventArgs GetRangeActionOrSelf( this NotifyCollectionChangedEventArgs source ) + { + if( source == null ) + throw new ArgumentNullException( "source" ); + + var rangeEventArgs = source as NotifyRangeCollectionChangedEventArgs; + if( rangeEventArgs != null ) + return rangeEventArgs.OriginalEventArgs; + + return source; + } + + internal static object GetReplacement( this NotifyCollectionChangedEventArgs source, object item ) + { + if( source == null ) + throw new ArgumentNullException( "source" ); + + var result = default( object ); + + if( item != null ) + { + var batch = source as NotifyBatchCollectionChangedEventArgs; + if( batch != null ) + { + if( !batch.Replacements.TryGetValue( item, out result ) ) + { + result = null; + } + } + else if( source.Action == NotifyCollectionChangedAction.Replace ) + { + var oldItems = source.OldItems; + var newItems = source.NewItems; + + if( ( oldItems != null ) && ( newItems != null ) ) + { + var index = oldItems.IndexOf( item ); + if( index >= 0 ) + { + result = newItems[ index ]; + } + } + } + } + + return result; + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/NotifyRangeCollectionChangedEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/NotifyRangeCollectionChangedEventArgs.cs similarity index 96% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/NotifyRangeCollectionChangedEventArgs.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/NotifyRangeCollectionChangedEventArgs.cs index 4292c81a..5482024d 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/NotifyRangeCollectionChangedEventArgs.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/NotifyRangeCollectionChangedEventArgs.cs @@ -1,51 +1,51 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Specialized; - -namespace Xceed.Wpf.DataGrid -{ - internal sealed class NotifyRangeCollectionChangedEventArgs : NotifyCollectionChangedEventArgs - { - #region Constructor - - internal NotifyRangeCollectionChangedEventArgs( NotifyCollectionChangedEventArgs args ) - : base( NotifyCollectionChangedAction.Reset ) - { - if( args == null ) - throw new ArgumentNullException( "args" ); - - m_originalEventArgs = args; - } - - #endregion - - #region OriginalEventArgs Property - - internal NotifyCollectionChangedEventArgs OriginalEventArgs - { - get - { - return m_originalEventArgs; - } - } - - private readonly NotifyCollectionChangedEventArgs m_originalEventArgs; - - #endregion - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Specialized; + +namespace Xceed.Wpf.DataGrid +{ + internal sealed class NotifyRangeCollectionChangedEventArgs : NotifyCollectionChangedEventArgs + { + #region Constructor + + internal NotifyRangeCollectionChangedEventArgs( NotifyCollectionChangedEventArgs args ) + : base( NotifyCollectionChangedAction.Reset ) + { + if( args == null ) + throw new ArgumentNullException( "args" ); + + m_originalEventArgs = args; + } + + #endregion + + #region OriginalEventArgs Property + + internal NotifyCollectionChangedEventArgs OriginalEventArgs + { + get + { + return m_originalEventArgs; + } + } + + private readonly NotifyCollectionChangedEventArgs m_originalEventArgs; + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/RealizedContainersRequestedEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/RealizedContainersRequestedEvent.cs similarity index 96% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/RealizedContainersRequestedEventArgs.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/RealizedContainersRequestedEvent.cs index e10c43a6..ccef5ae2 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/RealizedContainersRequestedEventArgs.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/RealizedContainersRequestedEvent.cs @@ -1,37 +1,37 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; - -namespace Xceed.Wpf.DataGrid -{ - internal class RealizedContainersRequestedEventArgs: EventArgs - { - public List RealizedContainers - { - get - { - return m_realizedContainers; - } - } - - private List m_realizedContainers = new List(); - } - - internal delegate void RealizedContainersRequestedEventHandler( object sender, RealizedContainersRequestedEventArgs e ); -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Xceed.Wpf.DataGrid +{ + internal class RealizedContainersRequestedEventArgs: EventArgs + { + public List RealizedContainers + { + get + { + return m_realizedContainers; + } + } + + private List m_realizedContainers = new List(); + } + + internal delegate void RealizedContainersRequestedEventHandler( object sender, RealizedContainersRequestedEventArgs e ); +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/RealizedContainersRequestedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/RealizedContainersRequestedEventManager.cs similarity index 97% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/RealizedContainersRequestedEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/RealizedContainersRequestedEventManager.cs index b932c4cc..d3783e53 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/RealizedContainersRequestedEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/RealizedContainersRequestedEventManager.cs @@ -1,74 +1,74 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class RealizedContainersRequestedEventManager: WeakEventManager - { - private RealizedContainersRequestedEventManager() - { - } - - public static void AddListener( ColumnCollection source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( ColumnCollection source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - ColumnCollection columns = ( ColumnCollection )source; - columns.RealizedContainersRequested += this.OnRealizedContainersRequested; - } - - protected override void StopListening( object source ) - { - ColumnCollection columns = ( ColumnCollection )source; - columns.RealizedContainersRequested -= this.OnRealizedContainersRequested; - } - - private static RealizedContainersRequestedEventManager CurrentManager - { - get - { - Type managerType = typeof( RealizedContainersRequestedEventManager ); - RealizedContainersRequestedEventManager currentManager = ( RealizedContainersRequestedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new RealizedContainersRequestedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnRealizedContainersRequested( object sender, RealizedContainersRequestedEventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class RealizedContainersRequestedEventManager: WeakEventManager + { + private RealizedContainersRequestedEventManager() + { + } + + public static void AddListener( ColumnCollection source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + public static void RemoveListener( ColumnCollection source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + ColumnCollection columns = ( ColumnCollection )source; + columns.RealizedContainersRequested += this.OnRealizedContainersRequested; + } + + protected override void StopListening( object source ) + { + ColumnCollection columns = ( ColumnCollection )source; + columns.RealizedContainersRequested -= this.OnRealizedContainersRequested; + } + + private static RealizedContainersRequestedEventManager CurrentManager + { + get + { + Type managerType = typeof( RealizedContainersRequestedEventManager ); + RealizedContainersRequestedEventManager currentManager = ( RealizedContainersRequestedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new RealizedContainersRequestedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnRealizedContainersRequested( object sender, RealizedContainersRequestedEventArgs args ) + { + this.DeliverEvent( sender, args ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/RequestBringIntoViewWeakEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/RequestBringIntoViewWeakEventManager.cs similarity index 85% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/RequestBringIntoViewWeakEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/RequestBringIntoViewWeakEventManager.cs index 5b689afe..858670ef 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/RequestBringIntoViewWeakEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/RequestBringIntoViewWeakEventManager.cs @@ -1,81 +1,73 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class RequestBringIntoViewWeakEventManager : WeakEventManager - { - #region Constructor - - private RequestBringIntoViewWeakEventManager() - { - } - - #endregion - - #region CurrentManager Static Property - - private static RequestBringIntoViewWeakEventManager CurrentManager - { - get - { - var managerType = typeof( RequestBringIntoViewWeakEventManager ); - var currentManager = ( RequestBringIntoViewWeakEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new RequestBringIntoViewWeakEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - #endregion - - public static void AddListener( FrameworkElement source, IWeakEventListener listener ) - { - RequestBringIntoViewWeakEventManager.CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( FrameworkElement source, IWeakEventListener listener ) - { - RequestBringIntoViewWeakEventManager.CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - var fe = ( FrameworkElement )source; - - fe.RequestBringIntoView += new RequestBringIntoViewEventHandler( this.OnEventRaised ); - } - - protected override void StopListening( object source ) - { - var fe = ( FrameworkElement )source; - - fe.RequestBringIntoView -= new RequestBringIntoViewEventHandler( this.OnEventRaised ); - } - - private void OnEventRaised( object sender, RequestBringIntoViewEventArgs e ) - { - this.DeliverEvent( sender, e ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class RequestBringIntoViewWeakEventManager : WeakEventManager + { + #region CurrentManager Static Property + + private static RequestBringIntoViewWeakEventManager CurrentManager + { + get + { + var managerType = typeof( RequestBringIntoViewWeakEventManager ); + var currentManager = ( RequestBringIntoViewWeakEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new RequestBringIntoViewWeakEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + #endregion + + internal static void AddListener( FrameworkElement source, IWeakEventListener listener ) + { + RequestBringIntoViewWeakEventManager.CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( FrameworkElement source, IWeakEventListener listener ) + { + RequestBringIntoViewWeakEventManager.CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + var fe = ( FrameworkElement )source; + + fe.RequestBringIntoView += new RequestBringIntoViewEventHandler( this.OnEventRaised ); + } + + protected override void StopListening( object source ) + { + var fe = ( FrameworkElement )source; + + fe.RequestBringIntoView -= new RequestBringIntoViewEventHandler( this.OnEventRaised ); + } + + private void OnEventRaised( object sender, RequestBringIntoViewEventArgs e ) + { + this.DeliverEvent( sender, e ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/RequestingDelayBringIntoViewAndFocusCurrentEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/RequestingDelayBringIntoViewAndFocusCurrentEventArgs.cs similarity index 96% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/RequestingDelayBringIntoViewAndFocusCurrentEventArgs.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/RequestingDelayBringIntoViewAndFocusCurrentEventArgs.cs index 0134c4e6..6ee4f79a 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/RequestingDelayBringIntoViewAndFocusCurrentEventArgs.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/RequestingDelayBringIntoViewAndFocusCurrentEventArgs.cs @@ -1,42 +1,42 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; - -namespace Xceed.Wpf.DataGrid -{ - internal class RequestingDelayBringIntoViewAndFocusCurrentEventArgs : EventArgs - { - internal RequestingDelayBringIntoViewAndFocusCurrentEventArgs( AutoScrollCurrentItemSourceTriggers trigger ) - { - m_trigger = trigger; - } - - #region Trigger Property - - internal AutoScrollCurrentItemSourceTriggers Trigger - { - get - { - return m_trigger; - } - } - - private readonly AutoScrollCurrentItemSourceTriggers m_trigger; - - #endregion - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; + +namespace Xceed.Wpf.DataGrid +{ + internal class RequestingDelayBringIntoViewAndFocusCurrentEventArgs : EventArgs + { + internal RequestingDelayBringIntoViewAndFocusCurrentEventArgs( AutoScrollCurrentItemSourceTriggers trigger ) + { + m_trigger = trigger; + } + + #region Trigger Property + + internal AutoScrollCurrentItemSourceTriggers Trigger + { + get + { + return m_trigger; + } + } + + private readonly AutoScrollCurrentItemSourceTriggers m_trigger; + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/RowValidationErrorRoutedEvent.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/RowValidationErrorRoutedEvent.cs similarity index 95% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/RowValidationErrorRoutedEvent.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/RowValidationErrorRoutedEvent.cs index 49ce8f3c..4385a741 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/RowValidationErrorRoutedEvent.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/RowValidationErrorRoutedEvent.cs @@ -1,68 +1,67 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Windows; -using System.Windows.Controls; - -namespace Xceed.Wpf.DataGrid -{ - public delegate void RowValidationErrorRoutedEventHandler( object sender, RowValidationErrorRoutedEventArgs e ); - - public class RowValidationErrorRoutedEventArgs : RoutedEventArgs - { - public RowValidationErrorRoutedEventArgs( RowValidationError rowValidationError ) - : base() - { - if( rowValidationError == null ) - throw new ArgumentNullException( "rowValidationError" ); - - m_rowValidationError = rowValidationError; - } - - public RowValidationErrorRoutedEventArgs( RoutedEvent routedEvent, RowValidationError rowValidationError ) - : base( routedEvent ) - { - if( rowValidationError == null ) - throw new ArgumentNullException( "rowValidationError" ); - - m_rowValidationError = rowValidationError; - } - - public RowValidationErrorRoutedEventArgs( RoutedEvent routedEvent, object source, RowValidationError rowValidationError ) - : base( routedEvent, source ) - { - if( rowValidationError == null ) - throw new ArgumentNullException( "rowValidationError" ); - - m_rowValidationError = rowValidationError; - } - - #region ValidationError PROPERTY - - public RowValidationError RowValidationError - { - get - { - return m_rowValidationError; - } - } - - private RowValidationError m_rowValidationError; - - #endregion ValidationError PROPERTY - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + public delegate void RowValidationErrorRoutedEventHandler( object sender, RowValidationErrorRoutedEventArgs e ); + + public class RowValidationErrorRoutedEventArgs : RoutedEventArgs + { + public RowValidationErrorRoutedEventArgs( RowValidationError rowValidationError ) + : base() + { + if( rowValidationError == null ) + throw new ArgumentNullException( "rowValidationError" ); + + m_rowValidationError = rowValidationError; + } + + public RowValidationErrorRoutedEventArgs( RoutedEvent routedEvent, RowValidationError rowValidationError ) + : base( routedEvent ) + { + if( rowValidationError == null ) + throw new ArgumentNullException( "rowValidationError" ); + + m_rowValidationError = rowValidationError; + } + + public RowValidationErrorRoutedEventArgs( RoutedEvent routedEvent, object source, RowValidationError rowValidationError ) + : base( routedEvent, source ) + { + if( rowValidationError == null ) + throw new ArgumentNullException( "rowValidationError" ); + + m_rowValidationError = rowValidationError; + } + + #region ValidationError PROPERTY + + public RowValidationError RowValidationError + { + get + { + return m_rowValidationError; + } + } + + private RowValidationError m_rowValidationError; + + #endregion ValidationError PROPERTY + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ScrollChangedWeakEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ScrollChangedWeakEventManager.cs similarity index 84% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ScrollChangedWeakEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ScrollChangedWeakEventManager.cs index 379745a2..3d713888 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ScrollChangedWeakEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ScrollChangedWeakEventManager.cs @@ -1,81 +1,74 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Controls; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class ScrollChangedWeakEventManager : WeakEventManager - { - private ScrollChangedWeakEventManager() - { - } - - public static void AddListener( ScrollViewer source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( ScrollViewer source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - ScrollViewer scrollViewer = source as ScrollViewer; - - if( scrollViewer != null ) - scrollViewer.ScrollChanged += this.ScrollViewer_ScrollChanged; - } - - protected override void StopListening( object source ) - { - ScrollViewer scrollViewer = source as ScrollViewer; - - if( scrollViewer != null ) - scrollViewer.ScrollChanged -= this.ScrollViewer_ScrollChanged; - } - - private static ScrollChangedWeakEventManager CurrentManager - { - get - { - Type managerType = typeof( ScrollChangedWeakEventManager ); - ScrollChangedWeakEventManager currentManager = - ( ScrollChangedWeakEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new ScrollChangedWeakEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void ScrollViewer_ScrollChanged( object sender, ScrollChangedEventArgs e ) - { - this.DeliverEvent( sender, e ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; +using System.Windows.Controls; + +namespace Xceed.Wpf.DataGrid +{ + internal class ScrollChangedWeakEventManager : WeakEventManager + { + internal static void AddListener( ScrollViewer source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( ScrollViewer source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + ScrollViewer scrollViewer = source as ScrollViewer; + + if( scrollViewer != null ) + scrollViewer.ScrollChanged += this.ScrollViewer_ScrollChanged; + } + + protected override void StopListening( object source ) + { + ScrollViewer scrollViewer = source as ScrollViewer; + + if( scrollViewer != null ) + scrollViewer.ScrollChanged -= this.ScrollViewer_ScrollChanged; + } + + private static ScrollChangedWeakEventManager CurrentManager + { + get + { + Type managerType = typeof( ScrollChangedWeakEventManager ); + ScrollChangedWeakEventManager currentManager = + ( ScrollChangedWeakEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new ScrollChangedWeakEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void ScrollViewer_ScrollChanged( object sender, ScrollChangedEventArgs e ) + { + this.DeliverEvent( sender, e ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/SelectionChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/SelectionChangedEventManager.cs similarity index 87% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/SelectionChangedEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/SelectionChangedEventManager.cs index 5c229dc9..5c5ab821 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/SelectionChangedEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/SelectionChangedEventManager.cs @@ -1,78 +1,74 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Windows; -using System.Windows.Controls.Primitives; -using System.Windows.Controls; - -namespace Xceed.Wpf.DataGrid -{ - internal class SelectionChangedEventManager : WeakEventManager - { - private SelectionChangedEventManager() - { - } - - public static void AddListener( Selector source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( Selector source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - Selector selector = ( Selector )source; - - if( selector != null ) - selector.SelectionChanged += new SelectionChangedEventHandler( this.Selector_SelectionChanged ); - } - - protected override void StopListening( object source ) - { - Selector selector = ( Selector )source; - - if( selector != null ) - selector.SelectionChanged -= new SelectionChangedEventHandler( this.Selector_SelectionChanged ); - } - - private static SelectionChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( SelectionChangedEventManager ); - SelectionChangedEventManager currentManager = ( SelectionChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new SelectionChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void Selector_SelectionChanged( object sender, SelectionChangedEventArgs e ) - { - this.DeliverEvent( sender, e ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; + +namespace Xceed.Wpf.DataGrid +{ + internal class SelectionChangedEventManager : WeakEventManager + { + internal static void AddListener( Selector source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( Selector source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + Selector selector = ( Selector )source; + + if( selector != null ) + selector.SelectionChanged += new SelectionChangedEventHandler( this.Selector_SelectionChanged ); + } + + protected override void StopListening( object source ) + { + Selector selector = ( Selector )source; + + if( selector != null ) + selector.SelectionChanged -= new SelectionChangedEventHandler( this.Selector_SelectionChanged ); + } + + private static SelectionChangedEventManager CurrentManager + { + get + { + Type managerType = typeof( SelectionChangedEventManager ); + SelectionChangedEventManager currentManager = ( SelectionChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new SelectionChangedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void Selector_SelectionChanged( object sender, SelectionChangedEventArgs e ) + { + this.DeliverEvent( sender, e ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/SelectionChangedInternalEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/SelectionChangedInternalEventArgs.cs similarity index 78% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/SelectionChangedInternalEventArgs.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/SelectionChangedInternalEventArgs.cs index 128258f1..247f799f 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/SelectionChangedInternalEventArgs.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/SelectionChangedInternalEventArgs.cs @@ -1,38 +1,35 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Xceed.Wpf.DataGrid -{ - internal class SelectionChangedInternalEventArgs : EventArgs - { - - public SelectionChangedInternalEventArgs(SelectionInfo selectionInfo) - { - this.SelectionInfo = selectionInfo; - } - - public SelectionInfo SelectionInfo - { - get; - private set; - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; + +namespace Xceed.Wpf.DataGrid +{ + internal class SelectionChangedInternalEventArgs : EventArgs + { + + internal SelectionChangedInternalEventArgs( SelectionInfo selectionInfo ) + { + this.SelectionInfo = selectionInfo; + } + + internal SelectionInfo SelectionInfo + { + get; + private set; + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/SelectionChangedInternalEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/SelectionChangedInternalEventManager.cs new file mode 100644 index 00000000..fbd32012 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/SelectionChangedInternalEventManager.cs @@ -0,0 +1,67 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; +using System.Windows.Threading; + +namespace Xceed.Wpf.DataGrid +{ + internal sealed class SelectionChangedInternalEventManager : WeakEventManager + { + internal static void AddListener( DataGridContext source, IWeakEventListener listener ) + { + SelectionChangedInternalEventManager.CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( DataGridContext source, IWeakEventListener listener ) + { + SelectionChangedInternalEventManager.CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + ( ( DataGridContext )source ).SelectionChangedInternal += new EventHandler( this.OnEventRaised ); + } + + protected override void StopListening( object source ) + { + ( ( DataGridContext )source ).SelectionChangedInternal -= new EventHandler( this.OnEventRaised ); + } + + private static SelectionChangedInternalEventManager CurrentManager + { + get + { + var managerType = typeof( SelectionChangedInternalEventManager ); + var currentManager = ( SelectionChangedInternalEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new SelectionChangedInternalEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnEventRaised( object sender, SelectionChangedInternalEventArgs e ) + { + this.DeliverEvent( sender, e ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ThemeChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ThemeChangedEventManager.cs similarity index 83% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ThemeChangedEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ThemeChangedEventManager.cs index 719e0dba..cdf6af77 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ThemeChangedEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ThemeChangedEventManager.cs @@ -1,75 +1,68 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class ThemeChangedEventManager : WeakEventManager - { - private ThemeChangedEventManager() - { - } - - public static void AddListener( DataGridControl source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( DataGridControl source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - DataGridControl dataGridControl = ( DataGridControl )source; - dataGridControl.ThemeChanged += new EventHandler( this.OnThemeChanged ); - } - - protected override void StopListening( object source ) - { - DataGridControl dataGridControl = ( DataGridControl )source; - dataGridControl.ThemeChanged -= new EventHandler( this.OnThemeChanged ); - } - - private static ThemeChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( ThemeChangedEventManager ); - ThemeChangedEventManager currentManager = ( ThemeChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new ThemeChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnThemeChanged( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class ThemeChangedEventManager : WeakEventManager + { + internal static void AddListener( DataGridControl source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( DataGridControl source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + DataGridControl dataGridControl = ( DataGridControl )source; + dataGridControl.ThemeChanged += new EventHandler( this.OnThemeChanged ); + } + + protected override void StopListening( object source ) + { + DataGridControl dataGridControl = ( DataGridControl )source; + dataGridControl.ThemeChanged -= new EventHandler( this.OnThemeChanged ); + } + + private static ThemeChangedEventManager CurrentManager + { + get + { + Type managerType = typeof( ThemeChangedEventManager ); + ThemeChangedEventManager currentManager = ( ThemeChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new ThemeChangedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnThemeChanged( object sender, EventArgs args ) + { + this.DeliverEvent( sender, args ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ViewChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ViewChangedEventManager.cs similarity index 86% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ViewChangedEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ViewChangedEventManager.cs index 543df4e3..18730990 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ViewChangedEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/ViewChangedEventManager.cs @@ -1,72 +1,68 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class ViewChangedEventManager : WeakEventManager - { - private ViewChangedEventManager() - { - } - - public static void AddListener( DataGridControl source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( DataGridControl source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - DataGridControl dataGridControl = ( DataGridControl )source; - dataGridControl.ViewChanged += new EventHandler( this.OnViewChanged ); - } - - protected override void StopListening( object source ) - { - DataGridControl dataGridControl = ( DataGridControl )source; - dataGridControl.ViewChanged -= new EventHandler( this.OnViewChanged ); - } - - private static ViewChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( ViewChangedEventManager ); - ViewChangedEventManager currentManager = ( ViewChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new ViewChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnViewChanged( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class ViewChangedEventManager : WeakEventManager + { + internal static void AddListener( DataGridControl source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( DataGridControl source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + DataGridControl dataGridControl = ( DataGridControl )source; + dataGridControl.ViewChanged += new EventHandler( this.OnViewChanged ); + } + + protected override void StopListening( object source ) + { + DataGridControl dataGridControl = ( DataGridControl )source; + dataGridControl.ViewChanged -= new EventHandler( this.OnViewChanged ); + } + + private static ViewChangedEventManager CurrentManager + { + get + { + Type managerType = typeof( ViewChangedEventManager ); + ViewChangedEventManager currentManager = ( ViewChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new ViewChangedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnViewChanged( object sender, EventArgs args ) + { + this.DeliverEvent( sender, args ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/VirtualizingCellCollectionChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/VirtualizingCellCollectionChangedEventManager.cs similarity index 94% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/VirtualizingCellCollectionChangedEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/VirtualizingCellCollectionChangedEventManager.cs index a70e02b5..f82d3ef9 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/VirtualizingCellCollectionChangedEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Events)/VirtualizingCellCollectionChangedEventManager.cs @@ -1,81 +1,78 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class VirtualizingCellCollectionChangedEventManager : WeakEventManager - { - internal static void AddListener( VirtualizingCellCollection source, IWeakEventListener listener ) - { - VirtualizingCellCollectionChangedEventManager.CurrentManager.ProtectedAddListener( source, listener ); - } - - internal static void RemoveListener( VirtualizingCellCollection source, IWeakEventListener listener ) - { - VirtualizingCellCollectionChangedEventManager.CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - VirtualizingCellCollection virtualizingCellCollection = source as VirtualizingCellCollection; - if( source == null ) - { - throw new InvalidOperationException( "An attempt was made to use a source other than a VirtualizingCellCollection" ); - } - - virtualizingCellCollection.CollectionChanged += this.OnVirtualizingCellCollectionChanged; - } - - protected override void StopListening( object source ) - { - VirtualizingCellCollection virtualizingCellCollection = source as VirtualizingCellCollection; - if( source == null ) - { - throw new InvalidOperationException( "An attempt was made to use a source other than a VirtualizingCellCollection" ); - } - - virtualizingCellCollection.CollectionChanged -= this.OnVirtualizingCellCollectionChanged; - } - - private static VirtualizingCellCollectionChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( VirtualizingCellCollectionChangedEventManager ); - VirtualizingCellCollectionChangedEventManager currentManager = WeakEventManager.GetCurrentManager( managerType ) as VirtualizingCellCollectionChangedEventManager; - - if( currentManager == null ) - { - currentManager = new VirtualizingCellCollectionChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnVirtualizingCellCollectionChanged( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class VirtualizingCellCollectionChangedEventManager : WeakEventManager + { + internal static void AddListener( VirtualizingCellCollection source, IWeakEventListener listener ) + { + VirtualizingCellCollectionChangedEventManager.CurrentManager.ProtectedAddListener( source, listener ); + } + + internal static void RemoveListener( VirtualizingCellCollection source, IWeakEventListener listener ) + { + VirtualizingCellCollectionChangedEventManager.CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + VirtualizingCellCollection virtualizingCellCollection = source as VirtualizingCellCollection; + if( source == null ) + { + throw new InvalidOperationException( "An attempt was made to use a source other than a VirtualizingCellCollection" ); + } + + virtualizingCellCollection.CollectionChanged += this.OnVirtualizingCellCollectionChanged; + } + + protected override void StopListening( object source ) + { + VirtualizingCellCollection virtualizingCellCollection = source as VirtualizingCellCollection; + if( source == null ) + { + throw new InvalidOperationException( "An attempt was made to use a source other than a VirtualizingCellCollection" ); + } + + virtualizingCellCollection.CollectionChanged -= this.OnVirtualizingCellCollectionChanged; + } + + private static VirtualizingCellCollectionChangedEventManager CurrentManager + { + get + { + Type managerType = typeof( VirtualizingCellCollectionChangedEventManager ); + VirtualizingCellCollectionChangedEventManager currentManager = WeakEventManager.GetCurrentManager( managerType ) as VirtualizingCellCollectionChangedEventManager; + + if( currentManager == null ) + { + currentManager = new VirtualizingCellCollectionChangedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnVirtualizingCellCollectionChanged( object sender, EventArgs args ) + { + this.DeliverEvent( sender, args ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/DataGridForeignKeyConverter.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/DataGridForeignKeyConverter.cs new file mode 100644 index 00000000..da972812 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/DataGridForeignKeyConverter.cs @@ -0,0 +1,141 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; + +namespace Xceed.Wpf.DataGrid +{ + public class DataGridForeignKeyConverter : ForeignKeyConverter + { + public DataGridForeignKeyConverter() + { + } + + public override object GetValueFromKey( object key, ForeignKeyConfiguration configuration ) + { + var itemsSource = configuration.ItemsSource; + if( itemsSource == null ) + return key; + + if( ( itemsSource is DataView ) || ( itemsSource is DataTable ) ) + return new DataTableForeignKeyConverter().GetValueFromKey( key, configuration ); + + return this.GetValueFromKeyCore( key, itemsSource, configuration.ValuePath, configuration.DisplayMemberPath ); + } + + public override object GetKeyFromValue( object value, ForeignKeyConfiguration configuration ) + { + if( value == null ) + return null; + + var displayMemberPath = configuration.DisplayMemberPath; + if( string.IsNullOrWhiteSpace( displayMemberPath ) ) + return value; + + var valuePath = configuration.ValuePath; + if( string.IsNullOrWhiteSpace( valuePath ) ) + return value; + + var itemsSource = configuration.ItemsSource; + if( itemsSource == null ) + return value; + + if( ( itemsSource is DataView ) || ( itemsSource is DataTable ) ) + return new DataTableForeignKeyConverter().GetKeyFromValue( value, configuration ); + + try + { + var enumerator = itemsSource.GetEnumerator(); + enumerator.MoveNext(); + var firstItem = enumerator.Current; + var itemType = firstItem.GetType(); + var propertyInfo = itemType.GetProperty( displayMemberPath ); + + foreach( object item in itemsSource ) + { + if( item == null ) + continue; + + var displayValue = propertyInfo.GetValue( item, null ); + + if( value.Equals( displayValue ) ) + return itemType.GetProperty( valuePath ).GetValue( item, null ); + } + } + catch + { + //Swallow the exception, no need to terminate the application, just return the original value. + } + + return value; + } + + public override object GetValueFromKey( object key, DataGridForeignKeyDescription description ) + { + var itemsSource = description.ItemsSource; + if( itemsSource == null ) + return key; + + if( ( itemsSource is DataView ) || ( itemsSource is DataTable ) ) + return new DataTableForeignKeyConverter().GetValueFromKey( key, description ); + + return this.GetValueFromKeyCore( key, itemsSource, description.ValuePath, description.DisplayMemberPath ); + } + + private object GetValueFromKeyCore( object key, IEnumerable itemsSource, string valuePath, string displayMemberPath ) + { + if( key == null ) + return null; + + if( string.IsNullOrWhiteSpace( displayMemberPath ) ) + return key; + + if( string.IsNullOrWhiteSpace( valuePath ) ) + return key; + + try + { + var enumerator = itemsSource.GetEnumerator(); + enumerator.MoveNext(); + var firstItem = enumerator.Current; + var itemType = firstItem.GetType(); + var propertyInfo = itemType.GetProperty( valuePath ); + + foreach( object item in itemsSource ) + { + if( item == null ) + continue; + + var value = propertyInfo.GetValue( item, null ); + + if( key.Equals( value ) ) + return itemType.GetProperty( displayMemberPath ).GetValue( item, null ); + } + } + catch + { + //Swallow the exception, no need to terminate the application, just return the original value. + } + + return key; + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/DataTableForeignKeyConverter.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/DataTableForeignKeyConverter.cs index 5e8812b3..0ed005c4 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/DataTableForeignKeyConverter.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/DataTableForeignKeyConverter.cs @@ -19,6 +19,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; +using System.Collections; namespace Xceed.Wpf.DataGrid { @@ -28,14 +29,17 @@ namespace Xceed.Wpf.DataGrid { } + public override object GetValueFromKey( object key, ForeignKeyConfiguration configuration ) + { + return this.GetValueFromKeyCore( key, configuration.ItemsSource, configuration.ValuePath, configuration.DisplayMemberPath, true ); + } + public override object GetKeyFromValue( object value, ForeignKeyConfiguration configuration ) { - // When the Key changes, try to find the data row that has the new key. - // If it is not found, return null. - DataView dataView = configuration.ItemsSource as DataView; + var dataView = configuration.ItemsSource as DataView; if( dataView == null ) { - DataTable dataTable = configuration.ItemsSource as DataTable; + var dataTable = configuration.ItemsSource as DataTable; if( dataTable != null ) { dataView = dataTable.DefaultView; @@ -47,7 +51,7 @@ namespace Xceed.Wpf.DataGrid return value; } - DataRowView dataRow = value as DataRowView; + var dataRow = value as DataRowView; if( dataRow == null ) { @@ -59,14 +63,17 @@ namespace Xceed.Wpf.DataGrid } } - public override object GetValueFromKey( object key, ForeignKeyConfiguration configuration ) + public override object GetValueFromKey( object key, DataGridForeignKeyDescription description ) { - // When the Key changes, try to find the data row that has the new key. - // If it is not found, return null. - DataView dataView = configuration.ItemsSource as DataView; + return this.GetValueFromKeyCore( key, description.ItemsSource, description.ValuePath, description.DisplayMemberPath, false ); + } + + private object GetValueFromKeyCore( object key, IEnumerable itemsSource, string valuePath, string displayMemberPath, bool isConfiguration ) + { + var dataView = itemsSource as DataView; if( dataView == null ) { - DataTable dataTable = configuration.ItemsSource as DataTable; + var dataTable = itemsSource as DataTable; if( dataTable != null ) { dataView = dataTable.DefaultView; @@ -78,8 +85,6 @@ namespace Xceed.Wpf.DataGrid return key; } - string valuePath = configuration.ValuePath; - if( string.IsNullOrEmpty( valuePath ) ) { return key; @@ -111,18 +116,19 @@ namespace Xceed.Wpf.DataGrid dataRow = dataView[ index ]; } - object value = dataRow; - // Use the DisplayMemberPath if defined if( dataRow != null ) { - if( !string.IsNullOrEmpty( configuration.DisplayMemberPath ) ) + if( !string.IsNullOrEmpty( displayMemberPath ) ) { - value = dataRow[ configuration.DisplayMemberPath ]; + return dataRow[ displayMemberPath ]; } } - return value; + if( isConfiguration ) + return dataRow; + + return key; } } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ForeignKeyConfigNotifyCollectionChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyConfigNotifyCollectionChangedEventManager.cs similarity index 97% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ForeignKeyConfigNotifyCollectionChangedEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyConfigNotifyCollectionChangedEventManager.cs index a30082b8..0adf06c4 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ForeignKeyConfigNotifyCollectionChangedEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyConfigNotifyCollectionChangedEventManager.cs @@ -1,68 +1,68 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class ForeignKeyConfigNotifyCollectionChangedEventManager : WeakEventManager - { - public static void AddListener( ForeignKeyConfiguration source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( ForeignKeyConfiguration source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - var configuration = ( ForeignKeyConfiguration )source; - configuration.NotifiyCollectionChanged += new EventHandler( this.OnNotifiyCollectionChanged ); - } - - protected override void StopListening( object source ) - { - var configuration = ( ForeignKeyConfiguration )source; - configuration.NotifiyCollectionChanged -= new EventHandler( this.OnNotifiyCollectionChanged ); - } - - private static ForeignKeyConfigNotifyCollectionChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( ForeignKeyConfigNotifyCollectionChangedEventManager ); - var currentManager = ( ForeignKeyConfigNotifyCollectionChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new ForeignKeyConfigNotifyCollectionChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnNotifiyCollectionChanged( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class ForeignKeyConfigNotifyCollectionChangedEventManager : WeakEventManager + { + public static void AddListener( ForeignKeyConfiguration source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + public static void RemoveListener( ForeignKeyConfiguration source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + var configuration = ( ForeignKeyConfiguration )source; + configuration.NotifiyCollectionChanged += new EventHandler( this.OnNotifiyCollectionChanged ); + } + + protected override void StopListening( object source ) + { + var configuration = ( ForeignKeyConfiguration )source; + configuration.NotifiyCollectionChanged -= new EventHandler( this.OnNotifiyCollectionChanged ); + } + + private static ForeignKeyConfigNotifyCollectionChangedEventManager CurrentManager + { + get + { + Type managerType = typeof( ForeignKeyConfigNotifyCollectionChangedEventManager ); + var currentManager = ( ForeignKeyConfigNotifyCollectionChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new ForeignKeyConfigNotifyCollectionChangedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnNotifiyCollectionChanged( object sender, EventArgs args ) + { + this.DeliverEvent( sender, args ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyConfiguration.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyConfiguration.cs index 883c6dfb..1e3327aa 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyConfiguration.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyConfiguration.cs @@ -16,7 +16,6 @@ using System; using System.Collections; -using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Data; @@ -24,7 +23,6 @@ using System.Globalization; using System.Windows; using System.Windows.Controls; using System.Windows.Data; -using Xceed.Utils.Collections; namespace Xceed.Wpf.DataGrid { @@ -538,7 +536,7 @@ namespace Xceed.Wpf.DataGrid { foreach( object item in itemsSource ) { - DataRowView dataRowView = item as DataRowView; + var dataRowView = item as DataRowView; if( dataRowView != null ) { var value = dataRowView[ valuePath ]; @@ -567,76 +565,97 @@ namespace Xceed.Wpf.DataGrid return fieldValue; } - internal static void UpdateColumnsForeignKeyConfigurations( Dictionary columns, IEnumerable itemsSourceCollection, - Dictionary fieldDescriptors, bool autoCreateForeignKeyConfigurations ) + internal static void UpdateColumnsForeignKeyConfigurations( + ObservableColumnCollection columns, + IEnumerable itemsSourceCollection, + PropertyDescriptionRouteDictionary propertyDescriptions, + bool autoCreateForeignKeyConfigurations ) { - DataGridCollectionViewBase collectionViewBase = itemsSourceCollection as DataGridCollectionViewBase; - + var collectionViewBase = itemsSourceCollection as DataGridCollectionViewBase; if( collectionViewBase != null ) { ForeignKeyConfiguration.UpdateColumnsForeignKeyConfigurationsFromDataGridCollectionView( columns, collectionViewBase.ItemProperties, autoCreateForeignKeyConfigurations ); } else { - ForeignKeyConfiguration.UpdateColumnsForeignKeyConfigurationsFromFieldDescriptors( columns, fieldDescriptors, autoCreateForeignKeyConfigurations ); + ForeignKeyConfiguration.UpdateColumnsForeignKeyConfigurationsFromPropertyDescriptions( columns, propertyDescriptions, autoCreateForeignKeyConfigurations ); } } // If a DataGridCollectionViewBase is used, get the ItemProperties it defines to be able to retreive DataGridForeignKeyDescription for each of them // to get the auto-detected ForeignKey ItemsSource (if any). // If a DataGridCollectionViewBase is not used, the ItemsSource must be manually specified on each Column in order to correctly display/edit the Data - internal static void UpdateColumnsForeignKeyConfigurationsFromDataGridCollectionView( Dictionary columns, DataGridItemPropertyCollection itemProperties, - bool autoCreateForeignKeyConfigurations ) + internal static void UpdateColumnsForeignKeyConfigurationsFromDataGridCollectionView( + ObservableColumnCollection columns, + DataGridItemPropertyCollection itemProperties, + bool autoCreateForeignKeyConfigurations ) { if( itemProperties == null ) return; - foreach( DataGridItemPropertyBase itemProperty in itemProperties ) + foreach( var itemProperty in itemProperties ) { - DataGridForeignKeyDescription description = itemProperty.ForeignKeyDescription; - - if( description == null ) - continue; + var description = itemProperty.ForeignKeyDescription; + if( description != null ) + { + var columnName = PropertyRouteParser.Parse( itemProperty ); + var column = ( columnName != null ) ? columns[ columnName ] as Column : null; - ColumnBase column; - columns.TryGetValue( itemProperty.Name, out column ); + if( column != null ) + { + ForeignKeyConfiguration.SynchronizeForeignKeyConfigurationFromForeignKeyDescription( column, description, autoCreateForeignKeyConfigurations ); + } + } - ForeignKeyConfiguration.SynchronizeForeignKeyConfigurationFromForeignKeyDescription( column as Column, description, autoCreateForeignKeyConfigurations ); + if( itemProperty.ItemPropertiesInternal != null ) + { + ForeignKeyConfiguration.UpdateColumnsForeignKeyConfigurationsFromDataGridCollectionView( + columns, + itemProperty.ItemPropertiesInternal, + autoCreateForeignKeyConfigurations ); + } } } - private static void UpdateColumnsForeignKeyConfigurationsFromFieldDescriptors( Dictionary columns, - Dictionary fieldDescriptors, - bool autoCreateForeignKeyConfigurations ) + private static void UpdateColumnsForeignKeyConfigurationsFromPropertyDescriptions( + ObservableColumnCollection columns, + PropertyDescriptionRouteDictionary propertyDescriptions, + bool autoCreateForeignKeyConfigurations ) { - if( columns == null ) - return; - - if( fieldDescriptors == null ) + if( ( columns == null ) || ( propertyDescriptions == null ) ) return; - foreach( ItemsSourceHelper.FieldDescriptor fieldDescriptor in fieldDescriptors.Values ) + foreach( var column in columns ) { - DataGridForeignKeyDescription description = fieldDescriptor.ForeignKeyDescription; + var targetColumn = column as Column; + if( targetColumn == null ) + continue; + + var key = PropertyRouteParser.Parse( targetColumn.FieldName ); + if( key == null ) + continue; - if( description == null ) + var propertyDescription = propertyDescriptions[ key ]; + if( propertyDescription == null ) continue; - ColumnBase column; - columns.TryGetValue( fieldDescriptor.Name, out column ); + var foreignKeyDescription = propertyDescription.Current.ForeignKeyDescription; + if( foreignKeyDescription == null ) + continue; - ForeignKeyConfiguration.SynchronizeForeignKeyConfigurationFromForeignKeyDescription( column as Column, description, autoCreateForeignKeyConfigurations ); + ForeignKeyConfiguration.SynchronizeForeignKeyConfigurationFromForeignKeyDescription( targetColumn, foreignKeyDescription, autoCreateForeignKeyConfigurations ); } } - internal static void SynchronizeForeignKeyConfigurationFromForeignKeyDescription( Column column, DataGridForeignKeyDescription description, - bool autoCreateForeignKeyConfigurations ) + internal static void SynchronizeForeignKeyConfigurationFromForeignKeyDescription( + Column column, + DataGridForeignKeyDescription description, + bool autoCreateForeignKeyConfigurations ) { if( ( description == null ) || ( column == null ) ) return; - ForeignKeyConfiguration configuration = column.ForeignKeyConfiguration; - + var configuration = column.ForeignKeyConfiguration; if( configuration == null ) { if( !autoCreateForeignKeyConfigurations ) @@ -677,14 +696,22 @@ namespace Xceed.Wpf.DataGrid #region IWeakEventListener Members bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) + { + return this.OnReceiveWeakEvent( managerType, sender, e ); + } + + protected virtual bool OnReceiveWeakEvent( Type managerType, object sender, EventArgs e ) { if( ( managerType == typeof( CollectionChangedEventManager ) ) || ( managerType == typeof( ListChangedEventManager ) ) ) { this.OnNotifiyCollectionChanged(); - return true; + } + else + { + return false; } - return false; + return true; } #endregion diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ForeignKeyConfigurationChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyConfigurationChangedEventManager.cs similarity index 97% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ForeignKeyConfigurationChangedEventManager.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyConfigurationChangedEventManager.cs index f4c64c5d..10db6557 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ForeignKeyConfigurationChangedEventManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyConfigurationChangedEventManager.cs @@ -1,72 +1,72 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class ForeignKeyConfigurationChangedEventManager : WeakEventManager - { - private ForeignKeyConfigurationChangedEventManager() - { - } - - public static void AddListener( Column source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( Column source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - Column column = ( Column )source; - column.ForeignKeyConfigurationChanged += new EventHandler( this.OnForeignKeyConfigurationChangedChanged ); - } - - protected override void StopListening( object source ) - { - Column column = ( Column )source; - column.ForeignKeyConfigurationChanged -= new EventHandler( this.OnForeignKeyConfigurationChangedChanged ); - } - - private static ForeignKeyConfigurationChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( ForeignKeyConfigurationChangedEventManager ); - ForeignKeyConfigurationChangedEventManager currentManager = ( ForeignKeyConfigurationChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new ForeignKeyConfigurationChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnForeignKeyConfigurationChangedChanged( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class ForeignKeyConfigurationChangedEventManager : WeakEventManager + { + private ForeignKeyConfigurationChangedEventManager() + { + } + + public static void AddListener( Column source, IWeakEventListener listener ) + { + CurrentManager.ProtectedAddListener( source, listener ); + } + + public static void RemoveListener( Column source, IWeakEventListener listener ) + { + CurrentManager.ProtectedRemoveListener( source, listener ); + } + + protected override void StartListening( object source ) + { + Column column = ( Column )source; + column.ForeignKeyConfigurationChanged += new EventHandler( this.OnForeignKeyConfigurationChangedChanged ); + } + + protected override void StopListening( object source ) + { + Column column = ( Column )source; + column.ForeignKeyConfigurationChanged -= new EventHandler( this.OnForeignKeyConfigurationChangedChanged ); + } + + private static ForeignKeyConfigurationChangedEventManager CurrentManager + { + get + { + Type managerType = typeof( ForeignKeyConfigurationChangedEventManager ); + ForeignKeyConfigurationChangedEventManager currentManager = ( ForeignKeyConfigurationChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); + + if( currentManager == null ) + { + currentManager = new ForeignKeyConfigurationChangedEventManager(); + WeakEventManager.SetCurrentManager( managerType, currentManager ); + } + + return currentManager; + } + } + + private void OnForeignKeyConfigurationChangedChanged( object sender, EventArgs args ) + { + this.DeliverEvent( sender, args ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyConverter.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyConverter.cs index e0980bdb..aea26416 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyConverter.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyConverter.cs @@ -24,16 +24,10 @@ namespace Xceed.Wpf.DataGrid { public abstract class ForeignKeyConverter { - #region Constructors - public ForeignKeyConverter() { } - #endregion - - #region Public Virtual Methods - public virtual object GetValueFromKey( object key, ForeignKeyConfiguration configuration ) { return key; @@ -44,6 +38,9 @@ namespace Xceed.Wpf.DataGrid return value; } - #endregion + public virtual object GetValueFromKey( object key, DataGridForeignKeyDescription description ) + { + return key; + } } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyDistinctValueItemContentControl.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyDistinctValueItemContentControl.cs new file mode 100644 index 00000000..a0e5eca2 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyDistinctValueItemContentControl.cs @@ -0,0 +1,154 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Data; + +namespace Xceed.Wpf.DataGrid +{ + internal class ForeignKeyDistinctValueItemContentControl : ForeignKeyContentControl + { + #region Static Fields + + private static Binding ParentAutoFilterControlBinding; + + #endregion + + #region Constructors + + static ForeignKeyDistinctValueItemContentControl() + { + ForeignKeyDistinctValueItemContentControl.ParentAutoFilterControlBinding = new Binding(); + ForeignKeyDistinctValueItemContentControl.ParentAutoFilterControlBinding.Mode = BindingMode.OneWay; + } + + public ForeignKeyDistinctValueItemContentControl() + { + } + + #endregion + + #region Private Methods + + #endregion + + #region DefaultCellContentTemplateBinding Private Static Property + + private static Binding DefaultCellContentTemplateBinding + { + get + { + if( ForeignKeyDistinctValueItemContentControl.DefaultCellContentTemplateBindingCache == null ) + { + ForeignKeyDistinctValueItemContentControl.DefaultCellContentTemplateBindingCache = new Binding(); + ForeignKeyDistinctValueItemContentControl.DefaultCellContentTemplateBindingCache.Mode = BindingMode.OneWay; + ForeignKeyDistinctValueItemContentControl.DefaultCellContentTemplateBindingCache.RelativeSource = new RelativeSource( RelativeSourceMode.Self ); + + ForeignKeyDistinctValueItemContentControl.DefaultCellContentTemplateBindingCache.Path = + new PropertyPath( "(0).(1).(2)", + Cell.ParentCellProperty, + Cell.ParentColumnProperty, + ColumnBase.CellContentTemplateProperty ); + } + + return ForeignKeyDistinctValueItemContentControl.DefaultCellContentTemplateBindingCache; + } + } + + private static Binding DefaultCellContentTemplateBindingCache; // = null; + + #endregion + + #region DefaultCellContentTemplateSelectorBinding Private Static Property + + private static Binding DefaultCellContentTemplateSelectorBinding + { + get + { + if( ForeignKeyDistinctValueItemContentControl.DefaultCellContentTemplateSelectorBindingCache == null ) + { + ForeignKeyDistinctValueItemContentControl.DefaultCellContentTemplateSelectorBindingCache = new Binding(); + ForeignKeyDistinctValueItemContentControl.DefaultCellContentTemplateSelectorBindingCache.Mode = BindingMode.OneWay; + ForeignKeyDistinctValueItemContentControl.DefaultCellContentTemplateSelectorBindingCache.RelativeSource = new RelativeSource( RelativeSourceMode.Self ); + + ForeignKeyDistinctValueItemContentControl.DefaultCellContentTemplateSelectorBindingCache.Path = + new PropertyPath( "(0).(1).(2)", + Cell.ParentCellProperty, + Cell.ParentColumnProperty, + ColumnBase.CellContentTemplateSelectorProperty ); + } + + return ForeignKeyDistinctValueItemContentControl.DefaultCellContentTemplateSelectorBindingCache; + } + } + + private static Binding DefaultCellContentTemplateSelectorBindingCache; + + #endregion + + #region DistinctValueItemTemplateBinding Private Static Property + + private static Binding DistinctValueItemTemplateBinding + { + get + { + if( ForeignKeyDistinctValueItemContentControl.DistinctValueItemTemplateBindingCache == null ) + { + ForeignKeyDistinctValueItemContentControl.DistinctValueItemTemplateBindingCache = new Binding(); + ForeignKeyDistinctValueItemContentControl.DistinctValueItemTemplateBindingCache.Mode = BindingMode.OneWay; + + + ForeignKeyDistinctValueItemContentControl.DistinctValueItemTemplateBindingCache.Path = + new PropertyPath( "DistinctValueItemTemplate" ); + } + + return ForeignKeyDistinctValueItemContentControl.DistinctValueItemTemplateBindingCache; + } + } + + private static Binding DistinctValueItemTemplateBindingCache; // = null; + + #endregion + + #region DefaultCellContentTemplateSelectorBinding Private Static Property + + private static Binding DistinctValueItemTemplateSelectorBinding + { + get + { + if( ForeignKeyDistinctValueItemContentControl.DistinctValueItemTemplateSelectorBindingCache == null ) + { + ForeignKeyDistinctValueItemContentControl.DistinctValueItemTemplateSelectorBindingCache = new Binding(); + ForeignKeyDistinctValueItemContentControl.DistinctValueItemTemplateSelectorBindingCache.Mode = BindingMode.OneWay; + + + ForeignKeyDistinctValueItemContentControl.DistinctValueItemTemplateSelectorBindingCache.Path = + new PropertyPath( "DistinctValueItemTemplateSelector" ); + } + + return ForeignKeyDistinctValueItemContentControl.DistinctValueItemTemplateSelectorBindingCache; + } + } + + private static Binding DistinctValueItemTemplateSelectorBindingCache; + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyScrollTipContentControl.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyScrollTipContentControl.cs index 4cf75fea..0e9589eb 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyScrollTipContentControl.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(ForeignKeys)/ForeignKeyScrollTipContentControl.cs @@ -14,12 +14,9 @@ ***********************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Windows; using System.Windows.Data; +using Xceed.Wpf.DataGrid.Views; namespace Xceed.Wpf.DataGrid { @@ -106,7 +103,7 @@ namespace Xceed.Wpf.DataGrid DataGridContext dataGridContext = DataGridControl.GetDataGridContext( this ); - Xceed.Wpf.DataGrid.Views.UIViewBase uiViewBase = null; + UIViewBase uiViewBase = null; if( dataGridContext != null ) { @@ -114,7 +111,7 @@ namespace Xceed.Wpf.DataGrid if( dataGridControl != null ) { - uiViewBase = dataGridControl.GetView() as Xceed.Wpf.DataGrid.Views.UIViewBase; + uiViewBase = dataGridControl.GetView() as UIViewBase; } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ContainersRemovedEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ContainersRemovedEvent.cs similarity index 96% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ContainersRemovedEventArgs.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ContainersRemovedEvent.cs index 69e0071b..bdf27017 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ContainersRemovedEventArgs.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ContainersRemovedEvent.cs @@ -1,48 +1,48 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; -using System.Collections.Specialized; - -namespace Xceed.Wpf.DataGrid -{ - internal delegate void ContainersRemovedEventHandler( object sender, ContainersRemovedEventArgs e ); - - internal class ContainersRemovedEventArgs : EventArgs - { - public ContainersRemovedEventArgs( IList removedContainers ) - { - if( removedContainers == null ) - throw new ArgumentNullException( "removedContainers" ); - - m_removedContainers = removedContainers; - } - - public IList RemovedContainers - { - get - { - return m_removedContainers; - } - } - - private IList m_removedContainers; - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Collections.Specialized; + +namespace Xceed.Wpf.DataGrid +{ + internal delegate void ContainersRemovedEventHandler( object sender, ContainersRemovedEventArgs e ); + + internal class ContainersRemovedEventArgs : EventArgs + { + public ContainersRemovedEventArgs( IList removedContainers ) + { + if( removedContainers == null ) + throw new ArgumentNullException( "removedContainers" ); + + m_removedContainers = removedContainers; + } + + public IList RemovedContainers + { + get + { + return m_removedContainers; + } + } + + private IList m_removedContainers; + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/CustomGeneratorChangedEvent.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/CustomGeneratorChangedEvent.cs new file mode 100644 index 00000000..9016ccfc --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/CustomGeneratorChangedEvent.cs @@ -0,0 +1,78 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal delegate void CustomGeneratorChangedEventHandler( object sender, CustomGeneratorChangedEventArgs e ); + + internal sealed class CustomGeneratorChangedEventArgs : EventArgs + { + private CustomGeneratorChangedEventArgs( NotifyCollectionChangedAction action, int count, IList containers ) + { + m_action = action; + m_count = count; + m_containers = containers; + } + + internal NotifyCollectionChangedAction Action + { + get + { + return m_action; + } + } + + internal int Count + { + get + { + return m_count; + } + } + + internal IList Containers + { + get + { + return m_containers; + } + } + + internal static CustomGeneratorChangedEventArgs Add( int count ) + { + return new CustomGeneratorChangedEventArgs( NotifyCollectionChangedAction.Add, count, null ); + } + + internal static CustomGeneratorChangedEventArgs Remove( int count, IList containers ) + { + return new CustomGeneratorChangedEventArgs( NotifyCollectionChangedAction.Remove, count, containers ); + } + + internal static CustomGeneratorChangedEventArgs Reset() + { + return new CustomGeneratorChangedEventArgs( NotifyCollectionChangedAction.Reset, 0, null ); + } + + private readonly NotifyCollectionChangedAction m_action; + private readonly int m_count; + private readonly IList m_containers; + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/CustomGeneratorChangedEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/CustomGeneratorChangedEventArgs.cs deleted file mode 100644 index dbc85a26..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/CustomGeneratorChangedEventArgs.cs +++ /dev/null @@ -1,128 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Collections.Specialized; -using System.Windows.Controls.Primitives; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal delegate void CustomGeneratorChangedEventHandler( object sender, CustomGeneratorChangedEventArgs e ); - - internal class CustomGeneratorChangedEventArgs : EventArgs - { - internal CustomGeneratorChangedEventArgs( NotifyCollectionChangedAction action, GeneratorPosition position, int index, int itemCount, int itemUICount ) - : this( action, position, index, new GeneratorPosition( -1, 0 ), -1, itemCount, itemUICount, null ) - { - - } - - internal CustomGeneratorChangedEventArgs( NotifyCollectionChangedAction action, GeneratorPosition position, int index, int itemCount, int itemUICount, IList removedContainers ) - : this( action, position, index, new GeneratorPosition( -1, 0 ), -1, itemCount, itemUICount, removedContainers ) - { - - } - - internal CustomGeneratorChangedEventArgs( NotifyCollectionChangedAction action, GeneratorPosition position, int index, GeneratorPosition oldPosition, int oldIndex, int itemCount, int itemUICount, IList removedContainers ) - { - _action = action; - _position = position; - _oldPosition = oldPosition; - _itemCount = itemCount; - _itemUICount = itemUICount; - _index = index; - _oldIndex = oldIndex; - m_removedContainers = removedContainers; - } - - public NotifyCollectionChangedAction Action - { - get - { - return _action; - } - } - - public int ItemCount - { - get - { - return _itemCount; - } - } - - public int ItemUICount - { - get - { - return _itemUICount; - } - } - - public GeneratorPosition OldPosition - { - get - { - return _oldPosition; - } - } - - public GeneratorPosition Position - { - get - { - return _position; - } - } - - public IList RemovedContainers - { - get - { - return m_removedContainers; - } - } - - public int Index - { - get - { - return _index; - } - } - - public int OldIndex - { - get - { - return _oldIndex; - } - } - - private readonly NotifyCollectionChangedAction _action; - private readonly int _itemCount; - private readonly int _itemUICount; - private readonly GeneratorPosition _oldPosition; - private readonly GeneratorPosition _position; - private readonly IList m_removedContainers; - private readonly int _index; - private readonly int _oldIndex; - - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/CustomItemContainerGenerator.Trace.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/CustomItemContainerGenerator.Trace.cs new file mode 100644 index 00000000..81cbe351 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/CustomItemContainerGenerator.Trace.cs @@ -0,0 +1,82 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Xceed.Wpf.DataGrid.Diagnostics; + +namespace Xceed.Wpf.DataGrid +{ + partial class CustomItemContainerGenerator + { + private IDisposable TraceBlock( DataGridTraceEventId eventId ) + { + return this.TraceBlock( eventId, ( string )null, null ); + } + + private IDisposable TraceBlock( DataGridTraceEventId eventId, params DataGridTraceArg[] args ) + { + return this.TraceBlock( eventId, null, args ); + } + + private IDisposable TraceBlock( DataGridTraceEventId eventId, string message, params DataGridTraceArg[] args ) + { + var traceSource = DataGridControlTraceSources.ItemContainerGeneratorSource; + if( !traceSource.ShouldTraceBlock() ) + return traceSource.NoTrace; + + return traceSource.TraceBlock( eventId, message, this.GetTraceArgs( args ).ToList() ); + } + + [Conditional( "TRACE" )] + private void TraceEvent( TraceEventType eventType, DataGridTraceEventId eventId ) + { + this.TraceEvent( eventType, eventId, ( string )null, null ); + } + + [Conditional( "TRACE" )] + private void TraceEvent( TraceEventType eventType, DataGridTraceEventId eventId, params DataGridTraceArg[] args ) + { + this.TraceEvent( eventType, eventId, null, args ); + } + + [Conditional( "TRACE" )] + private void TraceEvent( TraceEventType eventType, DataGridTraceEventId eventId, string message, params DataGridTraceArg[] args ) + { + var traceSource = DataGridControlTraceSources.ItemContainerGeneratorSource; + if( !traceSource.ShouldTrace( eventType ) ) + return; + + traceSource.TraceEvent( eventType, eventId, message, this.GetTraceArgs( args ).ToList() ); + } + + private IEnumerable GetTraceArgs( DataGridTraceArg[] args ) + { + if( ( args != null ) && ( args.Length > 0 ) ) + { + foreach( var arg in args ) + { + yield return arg; + } + } + + yield return DataGridTraceArgs.Generator( this ); + yield return DataGridTraceArgs.DataGridControl( m_dataGridControl ); + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/CustomItemContainerGenerator.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/CustomItemContainerGenerator.cs index 0bc8fe9c..eccc13cb 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/CustomItemContainerGenerator.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/CustomItemContainerGenerator.cs @@ -22,14 +22,13 @@ using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; using System.Linq; -using System.Text; using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Data; using Xceed.Utils.Collections; -using Xceed.Utils.Wpf; +using Xceed.Wpf.DataGrid.Diagnostics; using Xceed.Wpf.DataGrid.Views; namespace Xceed.Wpf.DataGrid @@ -41,29 +40,22 @@ namespace Xceed.Wpf.DataGrid INotifyPropertyChanged, IDataGridContextVisitable { - #region Static Fields - - private const int GlobalItemsResetThreshold = 10000; - - #endregion - internal static CustomItemContainerGenerator CreateGenerator( DataGridControl dataGridControl, CollectionView collectionView, DataGridContext dataGridContext ) { if( dataGridControl == null ) throw new ArgumentNullException( "dataGridControl" ); if( collectionView == null ) - DataGridException.ThrowSystemException( "collectionView", typeof( ArgumentNullException ), dataGridControl.Name ); + throw DataGridException.Create( "collectionView", dataGridControl ); if( dataGridContext == null ) - DataGridException.ThrowSystemException( "dataGridContext", typeof( ArgumentNullException ), dataGridControl.Name ); - - var log = new Log(); - log.StartUp(); + throw DataGridException.Create( "dataGridContext", dataGridControl ); + var recyclingPools = new CustomItemContainerGeneratorRecyclingPools(); + var ensureNodeTreeCreatedRequiredFlag = new BubbleDirtyFlag( true ); var handleGlobalItemsResetFlag = new InheritAutoResetFlag(); var deferDetailsRemapFlag = new LeveledAutoResetFlag(); - var generator = new CustomItemContainerGenerator( dataGridControl, collectionView, dataGridContext, log, handleGlobalItemsResetFlag, deferDetailsRemapFlag ); + var generator = new CustomItemContainerGenerator( dataGridControl, collectionView, dataGridContext, recyclingPools, ensureNodeTreeCreatedRequiredFlag, handleGlobalItemsResetFlag, deferDetailsRemapFlag ); dataGridContext.SetGenerator( generator ); @@ -76,18 +68,19 @@ namespace Xceed.Wpf.DataGrid throw new ArgumentNullException( "dataGridControl" ); if( collectionView == null ) - DataGridException.ThrowSystemException( "collectionView", typeof( ArgumentNullException ), dataGridControl.Name ); + throw DataGridException.Create( "collectionView", dataGridControl ); if( dataGridContext == null ) - DataGridException.ThrowSystemException( "dataGridContext", typeof( ArgumentNullException ), dataGridControl.Name ); + throw DataGridException.Create( "dataGridContext", dataGridControl ); if( masterGenerator == null ) - DataGridException.ThrowSystemException( "masterGenerator", typeof( ArgumentNullException ), dataGridControl.Name ); + throw DataGridException.Create( "masterGenerator", dataGridControl ); - var log = masterGenerator.m_log; + var recyclingPools = masterGenerator.m_recyclingPools; + var ensureNodeTreeCreatedRequiredFlag = new BubbleDirtyFlag( masterGenerator.m_ensureNodeTreeCreatedRequired, true ); var handleGlobalItemsResetFlag = new InheritAutoResetFlag( masterGenerator.m_handleGlobalItemsReset ); var deferDetailsRemapFlag = masterGenerator.m_deferDetailsRemap.GetChild(); - var generator = new CustomItemContainerGenerator( dataGridControl, collectionView, dataGridContext, log, handleGlobalItemsResetFlag, deferDetailsRemapFlag ); + var generator = new CustomItemContainerGenerator( dataGridControl, collectionView, dataGridContext, recyclingPools, ensureNodeTreeCreatedRequiredFlag, handleGlobalItemsResetFlag, deferDetailsRemapFlag ); dataGridContext.SetGenerator( generator ); @@ -98,21 +91,24 @@ namespace Xceed.Wpf.DataGrid DataGridControl dataGridControl, CollectionView collectionView, DataGridContext dataGridContext, - Log log, + CustomItemContainerGeneratorRecyclingPools recyclingPools, + BubbleDirtyFlag ensureNodeTreeCreatedRequiredFlag, InheritAutoResetFlag handleGlobalItemResetFlag, LeveledAutoResetFlag deferDetailsRemapFlag ) { Debug.Assert( dataGridControl != null ); Debug.Assert( collectionView != null ); Debug.Assert( dataGridContext != null ); - Debug.Assert( log != null ); + Debug.Assert( recyclingPools != null ); + Debug.Assert( ensureNodeTreeCreatedRequiredFlag != null ); Debug.Assert( handleGlobalItemResetFlag != null ); Debug.Assert( deferDetailsRemapFlag != null ); m_dataGridControl = dataGridControl; m_dataGridContext = dataGridContext; m_collectionView = collectionView; - m_log = log; + m_recyclingPools = recyclingPools; + m_ensureNodeTreeCreatedRequired = ensureNodeTreeCreatedRequiredFlag; m_handleGlobalItemsReset = handleGlobalItemResetFlag; m_deferDetailsRemap = deferDetailsRemapFlag; @@ -123,6 +119,7 @@ namespace Xceed.Wpf.DataGrid m_nodeFactory = new GeneratorNodeFactory( this.OnGeneratorNodeItemsCollectionChanged, this.OnGeneratorNodeGroupsCollectionChanged, + this.OnGeneratorNodeHeadersFootersCollectionChanged, this.OnGeneratorNodeExpansionStateChanged, this.OnGroupGeneratorNodeIsExpandedChanging, this.OnGroupGeneratorNodeIsExpandedChanged, @@ -197,6 +194,22 @@ namespace Xceed.Wpf.DataGrid #endregion + #region ForceReset Internal Property + + internal bool ForceReset + { + get + { + return m_flags[ ( int )CustomItemContainerGeneratorFlags.ForceReset ]; + } + set + { + m_flags[ ( int )CustomItemContainerGeneratorFlags.ForceReset ] = value; + } + } + + #endregion + #region Header Property public HeadersFootersGeneratorNode Header @@ -308,6 +321,8 @@ namespace Xceed.Wpf.DataGrid private IDisposable SetIsEnsuringNodeTreeCreated() { + m_ensureNodeTreeCreatedRequired.IsSet = false; + return m_ensureNodeTreeCreated.Set(); } @@ -315,6 +330,28 @@ namespace Xceed.Wpf.DataGrid #endregion + #region IsNodeTreeValid Private Property + + private bool IsNodeTreeValid + { + get + { + return !m_ensureNodeTreeCreatedRequired.IsSet; + } + } + + private void InvalidateNodeTree() + { + if( this.IsEnsuringNodeTreeCreated ) + return; + + m_ensureNodeTreeCreatedRequired.IsSet = true; + } + + private readonly BubbleDirtyFlag m_ensureNodeTreeCreatedRequired; + + #endregion + #region IsHandlingGlobalItemsReset Private Property private bool IsHandlingGlobalItemsReset @@ -335,8 +372,6 @@ namespace Xceed.Wpf.DataGrid private IDisposable SetIsHandlingGlobalItemsResetLocally() { - m_log.Assert( this, ( m_containersRemovedDeferCount != 0 ) || ( m_deferredContainersRemoved.Count == 0 ), "( m_containersRemovedDeferCount != 0 ) || ( m_deferredContainersRemoved.Count == 0 )" ); - return m_handleGlobalItemsReset.SetLocal(); } @@ -344,6 +379,25 @@ namespace Xceed.Wpf.DataGrid #endregion + #region IsItemsChangedInhibited Private Property + + private bool IsItemsChangedInhibited + { + get + { + return m_isItemsChangedInhibited.IsSet; + } + } + + private IDisposable InhibitItemsChanged() + { + return m_isItemsChangedInhibited.Set(); + } + + private readonly AutoResetFlag m_isItemsChangedInhibited = AutoResetFlagFactory.Create(); + + #endregion + #region DetailsChanged Event public event EventHandler DetailsChanged; @@ -354,39 +408,39 @@ namespace Xceed.Wpf.DataGrid internal event CustomGeneratorChangedEventHandler ItemsChanged; - private void SendRemoveEvent( GeneratorPosition remPos, int oldIndex, int remCount, int generatedRemCount, IList removedContainers ) + private void SendRemoveEvent( int count, IList containers ) { var handler = this.ItemsChanged; - if( handler == null ) + if( ( handler == null ) || ( count <= 0 ) || this.IsItemsChangedInhibited ) return; using( this.DeferDetailsRemap() ) { - handler.Invoke( this, new CustomGeneratorChangedEventArgs( NotifyCollectionChangedAction.Remove, remPos, oldIndex, remPos, oldIndex, remCount, generatedRemCount, removedContainers ) ); + handler.Invoke( this, CustomGeneratorChangedEventArgs.Remove( count, containers ) ); } } - private void SendAddEvent( GeneratorPosition genPos, int index, int addCount ) + private void SendAddEvent( int count ) { var handler = this.ItemsChanged; - if( handler == null ) + if( ( handler == null ) || ( count <= 0 ) || this.IsItemsChangedInhibited ) return; using( this.DeferDetailsRemap() ) { - handler.Invoke( this, new CustomGeneratorChangedEventArgs( NotifyCollectionChangedAction.Add, genPos, index, addCount, 0 ) ); + handler.Invoke( this, CustomGeneratorChangedEventArgs.Add( count ) ); } } private void SendResetEvent() { var handler = this.ItemsChanged; - if( handler == null ) + if( ( handler == null ) || this.IsItemsChangedInhibited ) return; using( this.DeferDetailsRemap() ) { - handler.Invoke( this, new CustomGeneratorChangedEventArgs( NotifyCollectionChangedAction.Reset, new GeneratorPosition(), 0, 0, 0 ) ); + handler.Invoke( this, CustomGeneratorChangedEventArgs.Reset() ); } } @@ -396,24 +450,32 @@ namespace Xceed.Wpf.DataGrid internal event ContainersRemovedEventHandler ContainersRemoved; - private void NotifyContainersRemoved( IList removedContainers ) + private void OnContainersRemoved( IList containers ) { - if( m_containersRemovedDeferCount > 0 ) - { - m_deferredContainersRemoved.AddRange( removedContainers ); - } - else if( removedContainers.Count > 0 ) - { - this.NotifyContainersRemoved( new ContainersRemovedEventArgs( removedContainers ) ); - } + var handler = this.ContainersRemoved; + if( ( handler == null ) || ( containers == null ) || ( containers.Count <= 0 ) ) + return; + + handler.Invoke( this, new ContainersRemovedEventArgs( containers ) ); } - private void NotifyContainersRemoved( ContainersRemovedEventArgs e ) + #endregion + + #region RecyclingCandidatesCleaned Internal Event + + internal event RecyclingCandidatesCleanedEventHandler RecyclingCandidatesCleaned; + + private void OnRecyclingCandidatesCleaned( object sender, RecyclingCandidatesCleanedEventArgs e ) { if( !this.IsRecyclingEnabled ) return; - var handler = this.ContainersRemoved; + foreach( DependencyObject container in e.RecyclingCandidates ) + { + this.ClearStatContext( container ); + } + + var handler = this.RecyclingCandidatesCleaned; if( handler == null ) return; @@ -422,528 +484,361 @@ namespace Xceed.Wpf.DataGrid #endregion - #region Logging Methods - - [Conditional( "CUSTOMLOG" )] - internal void ResetLog( string gridUniqueName ) + public void ResetGeneratorContent() { - m_log.StartUp( gridUniqueName ); + this.CleanupGenerator(); + this.EnsureNodeTreeCreated(); } - [Conditional( "LOG" )] - private void LogState() + public DependencyObject ContainerFromIndex( int itemIndex ) { - StringBuilder sb = new StringBuilder( 1024 ); - this.LogState( sb ); + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_ContainerFromIndex, DataGridTraceArgs.Index( itemIndex ) ) ) + { + if( this.IsHandlingGlobalItemsReset ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ContainerFromIndex, DataGridTraceMessages.CannotProcessOnReset, DataGridTraceArgs.Index( itemIndex ) ); + return null; + } - m_log.WriteLine( this, sb.ToString() ); - } + this.EnsureNodeTreeCreated(); - [Conditional( "LOG" )] - private void LogState( StringBuilder sb ) - { - var parent = m_dataGridContext.ParentDataGridContext; - if( parent != null ) - { - parent.CustomItemContainerGenerator.LogState( sb ); - } + var index = m_genPosToIndex.IndexOf( itemIndex ); + if( index >= 0 ) + { + var container = m_genPosToContainer[ index ]; - sb.Append( "Generator state : " ); - if( parent == null ) - { - sb.AppendLine( "MASTER" ); - } - else - { - sb.AppendLine( CustomItemContainerGenerator.FormatObjectId( "DETAIL - D", m_dataGridContext.ParentItem ) ); - } + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ContainerFromIndex, DataGridTraceMessages.ContainerFound, DataGridTraceArgs.Container( container ), DataGridTraceArgs.GeneratorIndex( index ), DataGridTraceArgs.Index( itemIndex ) ); - sb.AppendLine( string.Empty ); - sb.AppendLine( " m_genPosToContainer :" ); - for( int i = 0; i < m_genPosToContainer.Count; i++ ) - { - object value = m_genPosToContainer[ i ]; + var detailNode = m_genPosToNode[ index ] as DetailGeneratorNode; + if( detailNode == null ) + return container; - if( value == null ) - { - sb.AppendLine( " [ " + i.ToString() + " ] - null" ); + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ContainerFromIndex, DataGridTraceMessages.ContainerIsInDetail, DataGridTraceArgs.Container( container ), DataGridTraceArgs.GeneratorIndex( index ), DataGridTraceArgs.Index( itemIndex ), DataGridTraceArgs.Node( detailNode ) ); } else { - sb.AppendLine( " [ " + i.ToString() + " ] - " + value.GetHashCode() ); + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ContainerFromIndex, DataGridTraceMessages.ContainerNotFound, DataGridTraceArgs.Index( itemIndex ) ); } + + return null; } + } - sb.AppendLine( " m_genPosToIndex :" ); - for( int i = 0; i < m_genPosToIndex.Count; i++ ) + internal DependencyObject ContainerFromItem( object item ) + { + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_ContainerFromItem, DataGridTraceArgs.Item( item ) ) ) { - object value = m_genPosToIndex[ i ]; - - if( value == null ) + if( this.IsHandlingGlobalItemsReset ) { - sb.AppendLine( " [ " + i.ToString() + " ] - null" ); + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ContainerFromItem, DataGridTraceMessages.CannotProcessOnReset, DataGridTraceArgs.Item( item ) ); + return null; } - else + + this.EnsureNodeTreeCreated(); + + var index = this.FindFirstGeneratedIndexForLocalItem( item ); + if( index >= 0 ) { - sb.AppendLine( " [ " + i.ToString() + " ] - " + value.ToString() ); + var container = m_genPosToContainer[ index ]; + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ContainerFromItem, DataGridTraceMessages.ContainerFound, DataGridTraceArgs.Container( container ), DataGridTraceArgs.GeneratorIndex( index ), DataGridTraceArgs.Item( item ) ); + return container; } + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ContainerFromItem, DataGridTraceMessages.ContainerNotFound, DataGridTraceArgs.Item( item ) ); + return null; } + } - sb.AppendLine( " m_genPosToItem :" ); - for( int i = 0; i < m_genPosToItem.Count; i++ ) - { - object value = m_genPosToItem[ i ]; + internal List GetRealizedDataItemsForGroup( GroupGeneratorNode group ) + { + var count = m_genPosToNode.Count; + var items = new List( count ); - if( value == null ) - { - sb.AppendLine( " [ " + i.ToString() + " ] - null" ); - } - else + for( int i = 0; i < count; i++ ) + { + var node = m_genPosToNode[ i ] as ItemsGeneratorNode; + if( ( node != null ) && ( node.Parent == group ) ) { - sb.AppendLine( " [ " + i.ToString() + " ] - D" + value.GetHashCode() ); + items.Add( m_genPosToItem[ i ] ); } } - sb.AppendLine( " m_genPosToNode :" ); - for( int i = 0; i < m_genPosToNode.Count; i++ ) - { - object value = m_genPosToNode[ i ]; + return items; + } + + internal List GetRealizedDataItems() + { + var count = m_genPosToNode.Count; + var items = new List( count ); - if( value == null ) + for( int i = 0; i < count; i++ ) + { + var node = m_genPosToNode[ i ] as ItemsGeneratorNode; + if( node != null ) { - sb.AppendLine( " [ " + i.ToString() + " ] - null" ); + items.Add( m_genPosToItem[ i ] ); } - else - { - string prefix; + } - if( value is DetailGeneratorNode ) - { - prefix = "DN"; - } - else if( value is ItemsGeneratorNode ) - { - prefix = "IN"; - } - else if( value is CollectionGeneratorNode ) - { - prefix = "CN"; - } - else - { - prefix = "?N"; - } + return items; + } - int itemCount = ( value is GeneratorNode ) ? ( ( GeneratorNode )value ).ItemCount : 0; + internal object ItemFromContainer( DependencyObject container ) + { + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_ItemFromContainer, DataGridTraceArgs.Container( container ) ) ) + { + if( this.IsHandlingGlobalItemsReset ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ItemFromContainer, DataGridTraceMessages.CannotProcessOnReset, DataGridTraceArgs.Container( container ) ); + return null; + } - sb.AppendLine( " [ " + i.ToString() + " ] - " + prefix + value.GetHashCode() + " - ItemCount : " + itemCount ); + var dataItemStore = CustomItemContainerGenerator.GetDataItemProperty( container ); + if( ( dataItemStore == null ) || dataItemStore.IsEmpty ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ItemFromContainer, DataGridTraceMessages.ItemNotFound, DataGridTraceArgs.Container( container ) ); + return null; } - } - sb.AppendLine( " m_generatorDirection :" + m_generatorDirection.ToString() ); - sb.AppendLine( CustomItemContainerGenerator.FormatObjectId( " m_generatorCurrentDetail : DN", m_generatorCurrentDetail ) ); - sb.AppendLine( " m_generatorCurrentDetailIndex : " + m_generatorCurrentDetailIndex.ToString() ); - sb.AppendLine( " m_generatorCurrentDetailNodeIndex : " + m_generatorCurrentDetailNodeIndex.ToString() ); - sb.AppendLine( " m_generatorCurrentGlobalIndex : " + m_generatorCurrentGlobalIndex.ToString() ); - sb.AppendLine( " m_generatorCurrentOffset : " + m_generatorCurrentOffset.ToString() ); - sb.AppendLine( " m_generatorStatus : " + m_generatorStatus.ToString() ); - sb.AppendLine( " m_genPosToIndexUpdateInhibitCount : " + m_genPosToIndexUpdateInhibitCount.ToString() ); - sb.AppendLine( " IsEnsuringNodeTreeCreated : " + this.IsEnsuringNodeTreeCreated.ToString() ); - sb.AppendLine( " IsHandlingGlobalItemsReset : " + this.IsHandlingGlobalItemsReset.ToString() ); - sb.AppendLine( " IsDetailsRemapDeferred : " + this.IsDetailsRemapDeferred.ToString() ); + var dataItem = dataItemStore.Data; + var index = m_genPosToContainer.IndexOf( container ); - int newItemCount = m_cachedItemCount; - if( m_lastValidItemCountGeneration != m_currentGeneratorContentGeneration ) - { - if( m_startNode != null ) + if( index >= 0 ) { - int chainLength; - GeneratorNodeHelper.EvaluateChain( m_startNode, out newItemCount, out chainLength ); + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ItemFromContainer, DataGridTraceMessages.ContainerFound, DataGridTraceArgs.Container( container ), DataGridTraceArgs.GeneratorIndex( index ) ); + + var detailNode = m_genPosToNode[ index ] as DetailGeneratorNode; + if( detailNode != null ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ItemFromContainer, DataGridTraceMessages.ContainerIsInDetail, DataGridTraceArgs.Container( container ), DataGridTraceArgs.GeneratorIndex( index ), DataGridTraceArgs.Node( detailNode ) ); + return null; + } } else { - newItemCount = 0; + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ItemFromContainer, DataGridTraceMessages.ContainerNotFound, DataGridTraceArgs.Container( container ), DataGridTraceArgs.Item( dataItem ) ); } - } - sb.Append( " m_cachedItemCount : " + m_cachedItemCount.ToString() ); - if( newItemCount != m_cachedItemCount ) - { - sb.Append( " (needs refresh) - ItemCount : " + newItemCount.ToString() ); + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ItemFromContainer, DataGridTraceMessages.ItemFound, DataGridTraceArgs.Item( dataItem ), DataGridTraceArgs.Container( container ) ); + return dataItem; } - sb.AppendLine( string.Empty ); - - sb.AppendLine( string.Empty ); } - [Conditional( "LOG" )] - private void ValidateIndexOrder( string message ) + public int IndexFromItem( object item ) { - int count = m_genPosToIndex.Count; - int previousIndex = -1; - - for( int i = 0; i < count; i++ ) + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_IndexFromItem, DataGridTraceArgs.Item( item ) ) ) { - int tempIndex = m_genPosToIndex[ i ]; + if( item == null ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_IndexFromItem, DataGridTraceMessages.ItemNotFound, DataGridTraceArgs.Item( item ) ); + return -1; + } - if( tempIndex <= previousIndex ) + this.EnsureNodeTreeCreated(); + + if( m_startNode == null ) { - this.LogState(); + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_IndexFromItem, DataGridTraceMessages.EmptyTree, DataGridTraceArgs.Item( item ) ); + return -1; + } - if( string.IsNullOrEmpty( message ) ) - { - m_log.Fail( this, "### none sequential index detected." ); - } - else + var index = this.FindFirstGeneratedIndexForLocalItem( item ); + if( index >= 0 ) + { + var itemIndex = m_genPosToIndex[ index ]; + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_IndexFromItem, DataGridTraceMessages.IndexFound, DataGridTraceArgs.Index( itemIndex ), DataGridTraceArgs.GeneratorIndex( index ), DataGridTraceArgs.Item( item ) ); + return itemIndex; + } + else + { + //Note: Under that specific case, I do not want to search through collapsed group nodes... Effectivelly, an item "below" a collapsed group node + // Have no index as per the "item to index" interface of the generator. + var nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + var itemIndex = nodeHelper.FindItem( item ); + + if( itemIndex >= 0 ) { - m_log.Fail( this, "### none sequential index detected. " + message ); + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_IndexFromItem, DataGridTraceMessages.IndexFound, DataGridTraceArgs.Index( itemIndex ), DataGridTraceArgs.Node( nodeHelper.CurrentNode ), DataGridTraceArgs.Item( item ) ); + return itemIndex; } - - break; } - previousIndex = tempIndex; + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_IndexFromItem, DataGridTraceMessages.ItemNotFoundOrCollapsed, DataGridTraceArgs.Item( item ) ); + return -1; } } - [Conditional( "DEBUG" ), Conditional( "LOG" )] - private void CheckMasterItem( object dataItem ) + public object ItemFromIndex( int index ) { - if( m_masterToDetails.ContainsKey( dataItem ) ) - return; + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_ItemFromIndex, DataGridTraceArgs.Index( index ) ) ) + { + this.EnsureNodeTreeCreated(); - m_log.Fail( this, "m_masterToDetails do not contains the item from m_floatingDetails." ); - } + if( m_startNode == null ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ItemFromIndex, DataGridTraceMessages.EmptyTree, DataGridTraceArgs.Index( index ) ); + return null; + } - private static string FormatObjectId( string message, object item ) - { - string id = ( item == null ) ? "null" : item.GetHashCode().ToString(); + var nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + var item = nodeHelper.FindIndex( index ); - if( string.IsNullOrEmpty( message ) ) - return id; + if( item != null ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ItemFromIndex, DataGridTraceMessages.ItemFound, DataGridTraceArgs.Item( item ), DataGridTraceArgs.Node( nodeHelper.CurrentNode ), DataGridTraceArgs.Index( index ) ); + } + else + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ItemFromIndex, DataGridTraceMessages.ItemNotFound, DataGridTraceArgs.Index( index ) ); + } - return message + id; + return item; + } } - private readonly Log m_log; - - #endregion - - public static T FindContainerFromChild( DataGridControl dataGridControl, DependencyObject element ) where T : DependencyObject, IDataGridItemContainer + internal bool IsGroupRealized( Group group ) { - if( ( dataGridControl == null ) || ( element == null ) ) - return null; - - T container = null; + var groupNode = ( group != null ) ? group.GeneratorNode : null; + if( groupNode == null ) + return false; - while( element != null ) + foreach( var node in m_genPosToNode ) { - var currentDataGridContext = DataGridControl.GetDataGridContext( element ); - var currentDataGridControl = ( currentDataGridContext == null ) ? null : currentDataGridContext.DataGridControl; + var parentNode = node; - // We are only interested in containers that are part of the same grid. - if( currentDataGridControl == dataGridControl ) + // Find the first GroupGeneratorNode among its ancestors. + while( parentNode != null ) { - container = element as T; - - // We have found the container; - if( container != null ) + if( parentNode is GroupGeneratorNode ) break; + + parentNode = parentNode.Parent; } - // Since the element is the grid itself, we already know we will not find a suitable container beyond this point. - if( element == dataGridControl ) - break; + // Find out if the GroupGeneratorNode found is the group or a + // child of the target group. + while( parentNode != null ) + { + if( parentNode == groupNode ) + return true; - element = TreeHelper.GetParent( element ); + // The current node cannot be a child of the target group if + // the parent node is not a group. + parentNode = parentNode.Parent as GroupGeneratorNode; + } } - return container; + return false; } - public static FrameworkElement FindContainerFromChildOrRowSelectorOrSelf( DataGridControl dataGridControl, DependencyObject originalChildOrSelf ) + public int GetGroupIndex( Group group ) { - if( ( dataGridControl == null ) || ( originalChildOrSelf == null ) ) - return null; - - DependencyObject childOrSelf = originalChildOrSelf; - IDataGridItemContainer container = null; + if( group == null ) + throw DataGridException.Create( "group", m_dataGridControl ); - while( childOrSelf != null ) + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_GetGroupIndex, DataGridTraceArgs.Group( group ) ) ) { - var currentDataGridContext = DataGridControl.GetDataGridContext( childOrSelf ); - var currentDataGridControl = ( currentDataGridContext == null ) ? null : currentDataGridContext.DataGridControl; + this.EnsureNodeTreeCreated(); - // We are only interested in containers that are part of the same grid. - if( currentDataGridControl == dataGridControl ) + if( m_startNode == null ) { - container = childOrSelf as IDataGridItemContainer; + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_GetGroupIndex, DataGridTraceMessages.EmptyTree, DataGridTraceArgs.Group( group ) ); + return -1; + } - // We have found the container; - if( container != null ) - break; + var nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + if( nodeHelper.FindGroup( group.CollectionViewGroup ) ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_GetGroupIndex, DataGridTraceMessages.GroupFound, DataGridTraceArgs.Index( nodeHelper.Index ), DataGridTraceArgs.Node( nodeHelper.CurrentNode ), DataGridTraceArgs.Group( group ) ); + return nodeHelper.Index; } - // Since the element is the grid itself, we already know we will not find a suitable container beyond this point. - if( childOrSelf == dataGridControl ) - break; + foreach( var detailNode in this.GetDetailGeneratorNodes() ) + { + var index = detailNode.DetailGenerator.GetGroupIndex( group ); + if( index >= 0 ) + { + var detailIndex = this.FindGlobalIndexForDetailNode( detailNode ); + if( detailIndex >= 0 ) + { + var groupIndex = index + detailIndex; + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_GetGroupIndex, DataGridTraceMessages.GroupFound, DataGridTraceArgs.Index( groupIndex ), DataGridTraceArgs.Group( group ) ); + return groupIndex; + } + + this.TraceEvent( TraceEventType.Error, DataGridTraceEventId.CustomItemContainerGenerator_GetGroupIndex, DataGridTraceMessages.DetailNodeNotFound, DataGridTraceArgs.Group( group ) ); + return -1; + } + } - childOrSelf = TreeHelper.GetParent( childOrSelf ); + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_GetGroupIndex, DataGridTraceMessages.GroupNotFound, DataGridTraceArgs.Group( group ) ); + return -1; } + } - // RowSelector are handled differently. - if( container == null ) + public Group GetGroupFromItem( object item ) + { + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_GetGroupFromItem, DataGridTraceArgs.Item( item ) ) ) { - var target = DataGridControl.GetContainer( originalChildOrSelf ); + this.EnsureNodeTreeCreated(); - if( TreeHelper.IsDescendantOf( target, dataGridControl ) ) + if( m_startNode == null ) { - container = target as IDataGridItemContainer; + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_GetGroupFromItem, DataGridTraceMessages.EmptyTree, DataGridTraceArgs.Item( item ) ); + return null; } - } - dataGridControl.CustomItemContainerGenerator.m_log.Assert( ( container == null ) || ( container is FrameworkElement ), - "( container == null ) || ( container is FrameworkElement )" ); + GeneratorNode node; - return container as FrameworkElement; - } + var index = this.FindFirstGeneratedIndexForLocalItem( item ); + if( index >= 0 ) + { + node = m_genPosToNode[ index ]; - public void ResetGeneratorContent() - { - this.CleanupGenerator(); - this.EnsureNodeTreeCreated(); - } + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_GetGroupFromItem, DataGridTraceMessages.NodeFound, DataGridTraceArgs.Node( node ), DataGridTraceArgs.GeneratorIndex( index ), DataGridTraceArgs.Item( item ) ); + } + else + { + var nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + if( !nodeHelper.Contains( item ) ) //NOTE: this will only return items directly contained in this generator (not from details ) + throw DataGridException.Create( "An attempt was made to retrieve the group of an item that does not belong to the generator.", m_dataGridControl ); - public DependencyObject ContainerFromIndex( int itemIndex ) - { - if( this.IsHandlingGlobalItemsReset ) - return null; - - DependencyObject retval = null; - - this.EnsureNodeTreeCreated(); - - //retrieve the genenerator index for the index specified - int genPos = m_genPosToIndex.IndexOf( itemIndex ); - - //if the generator index is -1, then the item is not realized - if( genPos != -1 ) - { - DetailGeneratorNode detailNode = m_genPosToNode[ genPos ] as DetailGeneratorNode; - - if( detailNode == null ) - { - //remap the generator index on the container list. - retval = m_genPosToContainer[ genPos ]; - } - } - - return retval; - } - - internal DependencyObject ContainerFromItem( object item ) - { - if( this.IsHandlingGlobalItemsReset ) - return null; - - DependencyObject retval = null; - - //retrieve the genenerator index for the item specified - int genPos = this.FindFirstGeneratedIndexForLocalItem( item ); - - //if the generator index is -1, then the item is not realized - if( genPos != -1 ) - { - retval = m_genPosToContainer[ genPos ]; - } - - return retval; - } - - internal List GetRealizedDataItemsForGroup( GroupGeneratorNode group ) - { - int count = m_genPosToNode.Count; - List items = new List( count ); - - for( int i = 0; i < count; i++ ) - { - ItemsGeneratorNode node = m_genPosToNode[ i ] as ItemsGeneratorNode; + //if the nodeHelper was able to locate the content, use the nodeHelper's CurrentNode as the node for the item. + node = nodeHelper.CurrentNode; - if( ( node != null ) && ( node.Parent == group ) ) - { - items.Add( m_genPosToItem[ i ] ); + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_GetGroupFromItem, DataGridTraceMessages.NodeFound, DataGridTraceArgs.Node( node ), DataGridTraceArgs.Item( item ) ); } - } - - return items; - } - - internal List GetRealizedDataItems() - { - int count = m_genPosToNode.Count; - List items = new List( count ); - - for( int i = 0; i < count; i++ ) - { - ItemsGeneratorNode node = m_genPosToNode[ i ] as ItemsGeneratorNode; if( node != null ) { - items.Add( m_genPosToItem[ i ] ); - } - } - - return items; - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1822:MarkMembersAsStatic" )] - internal object ItemFromContainer( DependencyObject container ) - { - if( this.IsHandlingGlobalItemsReset ) - return null; - - var dataItemStore = CustomItemContainerGenerator.GetDataItemProperty( container ); - if( ( dataItemStore == null ) || dataItemStore.IsEmpty ) - return null; - - var dataItem = dataItemStore.Data; - var genPosIndex = m_genPosToContainer.IndexOf( container ); - - if( genPosIndex != -1 ) - { - DetailGeneratorNode detailNode = m_genPosToNode[ genPosIndex ] as DetailGeneratorNode; - if( detailNode != null ) - return null; - } - - return dataItem; - } - - public int IndexFromItem( object item ) - { - int retval = -1; - - if( item != null ) - { - this.EnsureNodeTreeCreated(); - - if( m_startNode != null ) - { - //if item is generated - int generatedIndex = this.FindFirstGeneratedIndexForLocalItem( item ); - if( generatedIndex != -1 ) - { - retval = m_genPosToIndex[ generatedIndex ]; - } - //if the item is not generated - else + var parentGroup = node.Parent as GroupGeneratorNode; + if( parentGroup != null ) { - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); - //Note: Under that specific case, I do not want to search through collapsed group nodes... Effectivelly, an item "below" a collapsed group node - // Have no index as per the "item to index" interface of the generator. - retval = nodeHelper.FindItem( item ); + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_GetGroupFromItem, DataGridTraceMessages.GroupFound, DataGridTraceArgs.Group( parentGroup.UIGroup ), DataGridTraceArgs.Node( parentGroup ), DataGridTraceArgs.Item( item ) ); + return parentGroup.UIGroup; } } - } - - return retval; - } - - public object ItemFromIndex( int index ) - { - object retval = null; - - this.EnsureNodeTreeCreated(); - - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); - - retval = nodeHelper.FindIndex( index ); - - return retval; - } - - public int GetGroupIndex( Group group ) - { - if( group == null ) - DataGridException.ThrowSystemException( "group", typeof( ArgumentNullException ), m_dataGridControl.Name ); - - this.EnsureNodeTreeCreated(); - - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); - - if( nodeHelper.FindGroup( group.CollectionViewGroup ) ) - return nodeHelper.Index; - //the item was not found in this generator's content... check all the detail generators - foreach( var detailNode in this.GetDetailGeneratorNodes() ) - { - int groupIndex = detailNode.DetailGenerator.GetGroupIndex( group ); - - if( groupIndex > -1 ) - return groupIndex + this.FindGlobalIndexForDetailNode( detailNode ); + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_GetGroupFromItem, DataGridTraceMessages.GroupNotFound, DataGridTraceArgs.Item( item ) ); + return null; } - - return -1; } - public Group GetGroupFromItem( object item ) + public Group GetGroupFromCollectionViewGroup( CollectionViewGroup collectionViewGroup ) { - Group retval = null; - - GeneratorNode nodeForItem = null; - this.EnsureNodeTreeCreated(); - //item might be in the "generated" list... much quicker to find-out if it is! - int itemGenPosIndex = this.FindFirstGeneratedIndexForLocalItem( item ); - if( itemGenPosIndex != -1 ) - { - //item is generated... - nodeForItem = m_genPosToNode[ itemGenPosIndex ]; - } - else - { - //only try to find the item is the generator has some content... - if( m_startNode != null ) - { - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); - if( nodeHelper.Contains( item ) ) //NOTE: this will only return items directly contained in this generator (not from details ) - { - //if the nodeHelper was able to locate the content, use the nodeHelper's CurrentNode as the node for the item. - nodeForItem = nodeHelper.CurrentNode; - } - else - { - DataGridException.ThrowSystemException( "An attempt was made to retrieve the group of an item that does not belong to the generator.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); - } - } - } - - if( nodeForItem != null ) - { - GroupGeneratorNode parentGroup = nodeForItem.Parent as GroupGeneratorNode; - if( parentGroup != null ) - { - retval = parentGroup.UIGroup; - } - } - - return retval; - } - - public Group GetGroupFromCollectionViewGroup( CollectionViewGroup collectionViewGroup ) - { - return this.GetGroupFromCollectionViewGroup( null, collectionViewGroup ); + return this.GetGroupFromCollectionViewGroupCore( collectionViewGroup ); } - public Group GetGroupFromCollectionViewGroup( Group parentUIGroup, CollectionViewGroup collectionViewGroup ) + private Group GetGroupFromCollectionViewGroupCore( CollectionViewGroup collectionViewGroup ) { - this.EnsureNodeTreeCreated(); - GroupGeneratorNode groupGeneratorNode = null; - - if( m_groupNodeMappingCache.TryGetValue( collectionViewGroup, out groupGeneratorNode ) ) - return groupGeneratorNode.UIGroup; + GroupGeneratorNode node; + if( m_groupNodeMappingCache.TryGetValue( collectionViewGroup, out node ) ) + return node.UIGroup; return null; } @@ -951,13 +846,11 @@ namespace Xceed.Wpf.DataGrid public CollectionViewGroup GetParentGroupFromItem( object item, bool recurseDetails ) { if( item == null ) - DataGridException.ThrowSystemException( "item", typeof( ArgumentNullException ), m_dataGridControl.Name ); - - CollectionViewGroup collectionViewGroup = null; + throw DataGridException.Create( "item", m_dataGridControl ); + CollectionViewGroup collectionViewGroup; if( !this.TryGetParentGroupFromItem( item, recurseDetails, out collectionViewGroup ) ) - DataGridException.ThrowSystemException( "An attempt was made to retrieve the parent group of an item that does not belong to the generator.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "An attempt was made to retrieve the parent group of an item that does not belong to the generator.", m_dataGridControl ); return collectionViewGroup; } @@ -972,15 +865,10 @@ namespace Xceed.Wpf.DataGrid this.EnsureNodeTreeCreated(); if( m_startNode == null ) - throw new DataGridInternalException( "Start node is null for the CollectionViewGroup.", m_dataGridControl ); + throw DataGridException.Create( "Start node is null for the CollectionViewGroup.", m_dataGridControl ); - //Invoke the helper that will check for the parent group within the local generator. if( this.TryGetParentGroupFromItemHelper( item, out collectionViewGroup ) ) - { - //if the item was found within the local generator, then return. return true; - } - //If the item was not in the local generator, continue with method. if( recurseDetails ) { @@ -1003,18 +891,16 @@ namespace Xceed.Wpf.DataGrid //----------------------------------------------- //1 - First check is to see of the item is a CVG. //----------------------------------------------- - CollectionViewGroup groupItem = item as CollectionViewGroup; + var groupItem = item as CollectionViewGroup; if( groupItem != null ) { - Group group = this.GetGroupFromCollectionViewGroup( groupItem ); + var group = this.GetGroupFromCollectionViewGroup( groupItem ); if( group != null ) { - GroupGeneratorNode groupGeneratorNode = group.GeneratorNode; + var groupGeneratorNode = group.GeneratorNode; if( groupGeneratorNode.Parent == null ) - { - //no parent for speficied item. return true; - } + //if the nodeHelper was able to locate the content, use the nodeHelper's CurrentNode as the node for the item. collectionViewGroup = ( ( GroupGeneratorNode )groupGeneratorNode.Parent ).CollectionViewGroup; return true; @@ -1030,15 +916,13 @@ namespace Xceed.Wpf.DataGrid //item might be in the "generated" list... much quicker to find-out if it is! //note: if the item belongs to a detail, then it will be excluded from the "fast" algo. - int itemGenPosIndex = this.FindFirstGeneratedIndexForLocalItem( item ); + var itemGenPosIndex = this.FindFirstGeneratedIndexForLocalItem( item ); if( itemGenPosIndex != -1 ) { //item was generated and was not from a DetailGeneratorNode if( m_genPosToNode[ itemGenPosIndex ].Parent == null ) - { - //no parent for speficied item. return true; - } + collectionViewGroup = ( ( GroupGeneratorNode )m_genPosToNode[ itemGenPosIndex ].Parent ).CollectionViewGroup; return true; } @@ -1048,8 +932,8 @@ namespace Xceed.Wpf.DataGrid //----------------------------------------------- if( item.GetType() == typeof( GroupHeaderFooterItem ) ) { - GroupHeaderFooterItem groupHeaderFooterItem = ( GroupHeaderFooterItem )item; - CollectionViewGroup parentGroup = groupHeaderFooterItem.Group; + var groupHeaderFooterItem = ( GroupHeaderFooterItem )item; + var parentGroup = groupHeaderFooterItem.Group; if( this.GetGroupFromCollectionViewGroup( parentGroup ) != null ) { @@ -1069,231 +953,201 @@ namespace Xceed.Wpf.DataGrid //----------------------------------------------- //if the item was not generated, then try to find the item as is within the generator's content - GeneratorNodeHelper finalNodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + var finalNodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); if( finalNodeHelper.AbsoluteFindItem( item ) ) { //item was not generated but was part of this generator if( finalNodeHelper.CurrentNode.Parent == null ) - { - //no parent for speficied item. return true; - } + collectionViewGroup = ( ( GroupGeneratorNode )finalNodeHelper.CurrentNode.Parent ).CollectionViewGroup; return true; } - else - { - return false; - } + + return false; } - public bool ExpandGroup( CollectionViewGroup group ) + internal bool ExpandGroup( CollectionViewGroup group ) { - bool groupExpanded = this.ExpandGroupCore( group, false ); - - if( !groupExpanded ) - DataGridException.ThrowSystemException( "An attempt was made to expand a group that does not exist.", typeof( InvalidOperationException ), m_dataGridControl.Name ); - - return groupExpanded; + return this.ExpandGroup( group, false ); } - internal bool ExpandGroupCore( CollectionViewGroup group, bool recurseDetails ) + internal bool ExpandGroup( CollectionViewGroup group, bool recurseDetails ) { if( this.Status == GeneratorStatus.GeneratingContainers ) - DataGridException.ThrowSystemException( "An attempt was made to expand a group while the generator is busy generating items.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "An attempt was made to expand a group while the generator is busy generating items.", m_dataGridControl ); if( group == null ) - DataGridException.ThrowSystemException( "group", typeof( ArgumentNullException ), m_dataGridControl.Name ); + throw DataGridException.Create( "group", m_dataGridControl ); - this.EnsureNodeTreeCreated(); + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_ExpandGroup, DataGridTraceArgs.Group( group ) ) ) + { + this.EnsureNodeTreeCreated(); - if( m_firstItem == null ) - throw new DataGridInternalException( "No GeneratorNode found for the group.", m_dataGridControl ); + if( m_firstItem == null ) + throw DataGridException.Create( "No GeneratorNode found for the group.", m_dataGridControl ); - Group uiGroup = this.GetGroupFromCollectionViewGroup( group ); - if( uiGroup != null ) - { - uiGroup.GeneratorNode.IsExpanded = true; - return true; - } + var uiGroup = this.GetGroupFromCollectionViewGroup( group ); + if( uiGroup != null ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ExpandGroup, DataGridTraceMessages.GroupFound, DataGridTraceArgs.Group( uiGroup ), DataGridTraceArgs.Node( uiGroup.GeneratorNode ), DataGridTraceArgs.Value( uiGroup.GeneratorNode.IsExpanded ) ); - if( recurseDetails ) - { - //the item was not found in this generator's content... check all the detail generators - foreach( var generator in this.GetDetailGenerators() ) + uiGroup.GeneratorNode.IsExpanded = true; + return true; + } + + if( recurseDetails ) { - // If the item is not found in the detail generator, it will return false; - // The "public" function call will throw if item is never found in itself or its details. - if( generator.ExpandGroupCore( group, recurseDetails ) ) - return true; + foreach( var generator in this.GetDetailGenerators() ) + { + // If the item is not found in the detail generator, it will return false; + if( generator.ExpandGroup( group, recurseDetails ) ) + return true; + } } - } - return false; + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ExpandGroup, DataGridTraceMessages.GroupNotFound, DataGridTraceArgs.Group( group ) ); + return false; + } } - public bool CollapseGroup( CollectionViewGroup group ) + internal bool CollapseGroup( CollectionViewGroup group ) { - bool groupCollapsed = this.CollapseGroupCore( group, false ); - - if( !groupCollapsed ) - DataGridException.ThrowSystemException( "An attempt was made to collapse a group that does not exist.", typeof( InvalidOperationException ), m_dataGridControl.Name ); - - return groupCollapsed; + return this.CollapseGroup( group, false ); } - internal bool CollapseGroupCore( CollectionViewGroup group, bool recurseDetails ) + internal bool CollapseGroup( CollectionViewGroup group, bool recurseDetails ) { if( this.Status == GeneratorStatus.GeneratingContainers ) - DataGridException.ThrowSystemException( "An attempt was made to collapse a group while the generator is busy generating items.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "An attempt was made to collapse a group while the generator is busy generating items.", m_dataGridControl ); if( group == null ) - DataGridException.ThrowSystemException( "group", typeof( ArgumentNullException ), m_dataGridControl.Name ); + throw DataGridException.Create( "group", m_dataGridControl ); - this.EnsureNodeTreeCreated(); + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_CollapseGroup, DataGridTraceArgs.Group( group ) ) ) + { + this.EnsureNodeTreeCreated(); - if( m_firstItem == null ) - throw new DataGridInternalException( "No GeneratorNode found for the group.", m_dataGridControl ); + if( m_firstItem == null ) + throw DataGridException.Create( "No GeneratorNode found for the group.", m_dataGridControl ); - Group uiGroup = this.GetGroupFromCollectionViewGroup( group ); - if( uiGroup != null ) - { - uiGroup.GeneratorNode.IsExpanded = false; - return true; - } + var uiGroup = this.GetGroupFromCollectionViewGroup( group ); + if( uiGroup != null ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_CollapseGroup, DataGridTraceMessages.GroupFound, DataGridTraceArgs.Group( uiGroup ), DataGridTraceArgs.Node( uiGroup.GeneratorNode ), DataGridTraceArgs.Value( uiGroup.GeneratorNode.IsExpanded ) ); - if( recurseDetails ) - { - //the item was not found in this generator's content... check all the detail generators - foreach( var generator in this.GetDetailGenerators() ) + uiGroup.GeneratorNode.IsExpanded = false; + return true; + } + + if( recurseDetails ) { - // If the item is not found in the detail generator, it will return false; - // The "public" function call will throw if item is never found in itself or its details. - if( generator.CollapseGroupCore( group, recurseDetails ) ) - return true; + foreach( var generator in this.GetDetailGenerators() ) + { + // If the item is not found in the detail generator, it will return false; + if( generator.CollapseGroup( group, recurseDetails ) ) + return true; + } } - } - return false; + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_CollapseGroup, DataGridTraceMessages.GroupNotFound, DataGridTraceArgs.Group( group ) ); + return false; + } } - public bool ToggleGroupExpansion( CollectionViewGroup group ) + internal bool ToggleGroupExpansion( CollectionViewGroup group ) { - bool groupToggled = this.ToggleGroupExpansionCore( group, false ); - - if( !groupToggled ) - DataGridException.ThrowSystemException( "An attempt was made to toggle a group that does not exist.", typeof( InvalidOperationException ), m_dataGridControl.Name ); - - return groupToggled; + return this.ToggleGroupExpansion( group, false ); } - internal bool ToggleGroupExpansionCore( CollectionViewGroup group, bool recurseDetails ) + internal bool ToggleGroupExpansion( CollectionViewGroup group, bool recurseDetails ) { if( this.Status == GeneratorStatus.GeneratingContainers ) - DataGridException.ThrowSystemException( "An attempt was made to a toggle a group's expansion while the generator is busy generating items.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "An attempt was made to toggle a group's expansion while the generator is busy generating items.", m_dataGridControl ); if( group == null ) - DataGridException.ThrowSystemException( "group", typeof( ArgumentNullException ), m_dataGridControl.Name ); + throw DataGridException.Create( "group", m_dataGridControl ); - this.EnsureNodeTreeCreated(); + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_ToggleGroupExpansion, DataGridTraceArgs.Group( group ) ) ) + { + this.EnsureNodeTreeCreated(); - if( m_firstItem == null ) - throw new DataGridInternalException( "No GeneratorNode found for the group.", m_dataGridControl ); + if( m_firstItem == null ) + throw DataGridException.Create( "No GeneratorNode found for the group.", m_dataGridControl ); - Group uiGroup = this.GetGroupFromCollectionViewGroup( group ); - if( uiGroup != null ) - { - GroupGeneratorNode groupNode = uiGroup.GeneratorNode; - groupNode.IsExpanded = !groupNode.IsExpanded; - return true; - } + var uiGroup = this.GetGroupFromCollectionViewGroup( group ); + if( uiGroup != null ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ToggleGroupExpansion, DataGridTraceMessages.GroupFound, DataGridTraceArgs.Group( uiGroup ), DataGridTraceArgs.Node( uiGroup.GeneratorNode ), DataGridTraceArgs.Value( uiGroup.GeneratorNode.IsExpanded ) ); - if( recurseDetails ) - { - //the item was not found in this generator's content... check all the detail generators - foreach( var generator in this.GetDetailGenerators() ) + var groupNode = uiGroup.GeneratorNode; + groupNode.IsExpanded = !groupNode.IsExpanded; + return true; + } + + if( recurseDetails ) { - try - { - return generator.ToggleGroupExpansionCore( group, recurseDetails ); - } - catch( InvalidOperationException ) + foreach( var generator in this.GetDetailGenerators() ) { - //if the item is not found in the detail generator, it will throw - //an invalid operation exception. If it doesn't throw, then it is - //safe to return the return value of the function. - - //otherwise, suppress this exception as ultimately, the "root" function call will - //throw if item is never found in itself or its details. + // If the item is not found in the detail generator, it will return false; + if( generator.ToggleGroupExpansion( group, recurseDetails ) ) + return true; } } - } - return false; + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ToggleGroupExpansion, DataGridTraceMessages.GroupNotFound, DataGridTraceArgs.Group( group ) ); + return false; + } } - public bool IsGroupExpanded( CollectionViewGroup group ) + internal bool? IsGroupExpanded( CollectionViewGroup group ) { - return this.IsGroupExpandedCore( group, false ); + return this.IsGroupExpanded( group, false ); } - internal bool IsGroupExpandedCore( CollectionViewGroup group, bool recurseDetails ) + internal bool? IsGroupExpanded( CollectionViewGroup group, bool recurseDetails ) { if( group == null ) - { - DataGridException.ThrowSystemException( "group", typeof( ArgumentNullException ), m_dataGridControl.Name ); - //Simply there to remove compile error. - return false; - } + throw DataGridException.Create( "group", m_dataGridControl ); - this.EnsureNodeTreeCreated(); + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_IsGroupExpanded, DataGridTraceArgs.Group( group ) ) ) + { + this.EnsureNodeTreeCreated(); - if( m_firstItem == null ) - throw new DataGridInternalException( "No GeneratorNode found for the group.", m_dataGridControl ); + if( m_firstItem == null ) + throw DataGridException.Create( "No GeneratorNode found for the group.", m_dataGridControl ); - Group uiGroup = this.GetGroupFromCollectionViewGroup( group ); - if( uiGroup != null ) - { - return uiGroup.GeneratorNode.IsExpanded; - } + var uiGroup = this.GetGroupFromCollectionViewGroup( group ); + if( uiGroup != null ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_IsGroupExpanded, DataGridTraceMessages.GroupFound, DataGridTraceArgs.Group( uiGroup ), DataGridTraceArgs.Node( uiGroup.GeneratorNode ), DataGridTraceArgs.Value( uiGroup.GeneratorNode.IsExpanded ) ); + return uiGroup.GeneratorNode.IsExpanded; + } - if( recurseDetails ) - { - //the group was not found in this generator, check in all the child generators for the group. - foreach( var generator in this.GetDetailGenerators() ) + if( recurseDetails ) { - try - { - return generator.IsGroupExpandedCore( group, recurseDetails ); - } - catch( InvalidOperationException ) + //the group was not found in this generator, check in all the child generators for the group. + foreach( var generator in this.GetDetailGenerators() ) { - //if the item is not found in the detail generator, it will throw - //an invalid operation exception. If it doesn't throw, then it is - //safe to return the return value of the function. - - //otherwise, suppress this exception as ultimately, the "root" function call will - //throw if item is never found in itself or its details. + var result = generator.IsGroupExpanded( group, recurseDetails ); + if( result.HasValue ) + return result.Value; } } - } - - DataGridException.ThrowSystemException( "An attempt was made to consult the expansion state of a group that does not exist.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); - //Simply there to remove compile error. - return false; + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_IsGroupExpanded, DataGridTraceMessages.GroupNotFound, DataGridTraceArgs.Group( group ) ); + return null; + } } internal void ExpandDetails( object dataItem ) { + } internal void CollapseDetails( object dataItem ) { + } internal void ToggleDetails( object dataItem ) @@ -1302,120 +1156,132 @@ namespace Xceed.Wpf.DataGrid internal bool AreDetailsExpanded( object dataItem ) { - if( dataItem == null ) - DataGridException.ThrowSystemException( "dataItem", typeof( ArgumentNullException ), m_dataGridControl.Name ); - - return m_masterToDetails.ContainsKey( dataItem ); + return false; } public void RemoveAllAndNotify() { if( m_startNode == null ) - return; //nothing to do, the generator is already in a "clean" state. - - //this message is issued by the DataGridContext when the VisibleColumns collection changes (re-ordering or changes to its content). - IList removedContainers = new List(); - this.RemoveGeneratedItems( int.MinValue, int.MaxValue, removedContainers ); + return; + this.RemoveGeneratedItems( int.MinValue, int.MaxValue, null ); this.SendResetEvent(); - - removedContainers.Clear(); - removedContainers = null; - - removedContainers = m_dataGridContext.RecyclingManager.Clear(); - - if( removedContainers.Count > 0 ) - { - this.NotifyContainersRemoved( removedContainers ); - } + this.ClearRecyclingPools(); } internal int FindIndexForItem( object item, DataGridContext dataGridContext ) { - int retval = -1; - bool recurse = false; - - this.EnsureNodeTreeCreated(); - - // If the seeked DataGridContext is this generator's context, the item should be here. - // When the seeked DataGridContext is null, search for the first item match no matter the generator's context. - if( ( m_dataGridContext == dataGridContext ) || ( dataGridContext == null ) ) + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_FindIndexForItem, DataGridTraceArgs.Item( item ) ) ) { - retval = this.IndexFromItem( item ); + this.EnsureNodeTreeCreated(); - // If the item wasn't found in this generator's context and that we don't have a precise target context, recurse. - if( ( retval == -1 ) && ( dataGridContext == null ) ) - recurse = true; - } - else - { - // The seeked DataGridContext is not this generator's context, recurse. - recurse = true; - } + // If the seeked DataGridContext is this generator's context, the item should be here. + // When the seeked DataGridContext is null, search for the first item match no matter the generator's context. + if( ( m_dataGridContext == dataGridContext ) || ( dataGridContext == null ) ) + { + var itemIndex = this.IndexFromItem( item ); + if( itemIndex >= 0 ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_FindIndexForItem, DataGridTraceMessages.ItemFound, DataGridTraceArgs.Item( item ), DataGridTraceArgs.Index( itemIndex ) ); + return itemIndex; + } - if( recurse ) - { - foreach( KeyValuePair> masterToDetails in m_masterToDetails ) + if( dataGridContext != null ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_FindIndexForItem, DataGridTraceMessages.ItemNotFound, DataGridTraceArgs.Item( item ) ); + return -1; + } + } + + foreach( var masterToDetails in m_masterToDetails ) { - int detailsTotalCount = 0; - foreach( DetailGeneratorNode detailNode in masterToDetails.Value ) + var detailsTotalCount = 0; + + foreach( var detailNode in masterToDetails.Value ) { - int itemIndex = detailNode.DetailGenerator.FindIndexForItem( item, dataGridContext ); - if( itemIndex != -1 ) + var itemIndex = detailNode.DetailGenerator.FindIndexForItem( item, dataGridContext ); + if( itemIndex >= 0 ) { - int masterIndex = this.IndexFromItem( masterToDetails.Key ); + var masterIndex = this.IndexFromItem( masterToDetails.Key ); + if( masterIndex >= 0 ) + { + var result = masterIndex + 1 + detailsTotalCount + itemIndex; - m_log.Assert( this, masterIndex != -1, "masterIndex != -1" ); + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_FindIndexForItem, DataGridTraceMessages.ItemFound, DataGridTraceArgs.Item( item ), DataGridTraceArgs.Index( result ) ); + return result; + } - retval = masterIndex + 1 + detailsTotalCount + itemIndex; - break; + this.TraceEvent( TraceEventType.Error, DataGridTraceEventId.CustomItemContainerGenerator_FindIndexForItem, DataGridTraceMessages.ItemNotFound, DataGridTraceArgs.Item( item ) ); + return -1; } detailsTotalCount += detailNode.ItemCount; } } - } - return retval; + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_FindIndexForItem, DataGridTraceMessages.ItemNotFound, DataGridTraceArgs.Item( item ) ); + return -1; + } } public DependencyObject GetRealizedContainerForIndex( int index ) { - //If the node tree is not created, then there can be no containers for the index. - if( m_startNode == null ) - return null; + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_GetRealizedContainerForIndex, DataGridTraceArgs.Index( index ) ) ) + { + this.EnsureNodeTreeCreated(); - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + if( m_startNode == null ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_GetRealizedContainerForIndex, DataGridTraceMessages.EmptyTree, DataGridTraceArgs.Index( index ) ); + return null; + } - if( !nodeHelper.FindNodeForIndex( index ) ) - DataGridException.ThrowSystemException( "The specified index does not correspond to an item in the generator.", - typeof( ArgumentException ), m_dataGridControl.Name, "index" ); + var nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + if( !nodeHelper.FindNodeForIndex( index ) ) + throw DataGridException.Create( "The specified index does not correspond to an item in the generator.", m_dataGridControl, "index" ); - int indexIndex = m_genPosToIndex.IndexOf( index ); - if( indexIndex == -1 ) - return null; + var indexIndex = m_genPosToIndex.IndexOf( index ); + if( indexIndex >= 0 ) + { + var container = m_genPosToContainer[ indexIndex ]; + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_GetRealizedContainerForIndex, DataGridTraceMessages.ContainerFound, DataGridTraceArgs.Container( container ), DataGridTraceArgs.GeneratorIndex( indexIndex ), DataGridTraceArgs.Index( index ) ); + return container; + } - return m_genPosToContainer[ indexIndex ]; + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_GetRealizedContainerForIndex, DataGridTraceMessages.ContainerNotFound, DataGridTraceArgs.Index( index ) ); + return null; + } } public int GetRealizedIndexForContainer( DependencyObject container ) { - int containerIndex = m_genPosToContainer.IndexOf( container ); - if( containerIndex == -1 ) - return -1; + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_GetRealizedIndexForContainer, DataGridTraceArgs.Container( container ) ) ) + { + this.EnsureNodeTreeCreated(); + + var index = m_genPosToContainer.IndexOf( container ); + if( index >= 0 ) + { + var itemIndex = m_genPosToIndex[ index ]; + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_GetRealizedIndexForContainer, DataGridTraceMessages.ContainerFound, DataGridTraceArgs.Index( itemIndex ), DataGridTraceArgs.GeneratorIndex( index ) ); + return itemIndex; + } - return m_genPosToIndex[ containerIndex ]; + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_GetRealizedIndexForContainer, DataGridTraceMessages.ContainerNotFound, DataGridTraceArgs.Container( container ) ); + return -1; + } } - internal List GetMasterIndexexWithExpandedDetails() + internal List GetMasterIndexesWithExpandedDetails() { - List masterIndexes = new List(); + var masterIndexes = new List(); - foreach( object dataItem in m_masterToDetails.Keys ) + foreach( var dataItem in m_masterToDetails.Keys ) { - int itemIndex = m_collectionView.IndexOf( dataItem ); - - m_log.Assert( this, itemIndex != -1, "itemIndex != -1" ); + var itemIndex = m_collectionView.IndexOf( dataItem ); + Debug.Assert( itemIndex >= 0 ); masterIndexes.Add( itemIndex ); } @@ -1427,16 +1293,15 @@ namespace Xceed.Wpf.DataGrid internal IEnumerable GetChildContextsForMasterItem( object item ) { - if( item != null ) - { - List detailNodes = null; + if( item == null ) + yield break; - if( m_masterToDetails.TryGetValue( item, out detailNodes ) ) + List detailNodes; + if( m_masterToDetails.TryGetValue( item, out detailNodes ) ) + { + foreach( var detailNode in detailNodes ) { - foreach( DetailGeneratorNode detailNode in detailNodes ) - { - yield return detailNode.DetailContext; - } + yield return detailNode.DetailContext; } } } @@ -1444,7 +1309,7 @@ namespace Xceed.Wpf.DataGrid public DataGridContext GetChildContext( object parentItem, string relationName ) { if( parentItem == null ) - DataGridException.ThrowSystemException( "parentItem", typeof( ArgumentNullException ), m_dataGridControl.Name ); + throw DataGridException.Create( "parentItem", m_dataGridControl ); this.EnsureNodeTreeCreated(); @@ -1459,9 +1324,7 @@ namespace Xceed.Wpf.DataGrid //Note: DetailContext.SourceDetailConfiguration will always be non-null, since we are looking for child contexts ( only the root master context can have a null //SourceDetailConfiguration. if( detailNode.DetailContext.SourceDetailConfiguration.RelationName == relationName ) - { return detailNode.DetailContext; - } } } @@ -1484,36 +1347,10 @@ namespace Xceed.Wpf.DataGrid { this.EnsureNodeTreeCreated(); - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + var nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); return nodeHelper.Contains( item ); } - public object[] GetNamesTreeFromGroup( CollectionViewGroup group ) - { - this.EnsureNodeTreeCreated(); - - Group uiGroup = this.GetGroupFromCollectionViewGroup( group ); - if( uiGroup != null ) - { - return uiGroup.GeneratorNode.NamesTree; - } - - return null; - } - - public CollectionViewGroup GetGroupFromNamesTree( object[] namesTree ) - { - this.EnsureNodeTreeCreated(); - - NamesTreeGroupFinderVisitor visitor = new NamesTreeGroupFinderVisitor( namesTree ); - - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); - bool visitWasStopped; - nodeHelper.ProcessVisit( m_dataGridContext, 0, int.MaxValue, visitor, DataGridContextVisitorType.Groups, false, out visitWasStopped ); - - return visitor.Group; - } - #region Sticky Headers Methods public List GenerateStickyHeaders( @@ -1522,7 +1359,7 @@ namespace Xceed.Wpf.DataGrid bool areGroupHeadersSticky, bool areParentRowsSticky ) { - List generatedStickyContainers = new List(); + var generatedStickyContainers = new List(); GeneratorNode containerNode; int containerRealizedIndex; @@ -1533,9 +1370,8 @@ namespace Xceed.Wpf.DataGrid out containerRealizedIndex, out containerDataItem ) ) { - GeneratorNodeHelper nodeHelper = null; - - DetailGeneratorNode detailNode = containerNode as DetailGeneratorNode; + var nodeHelper = default( GeneratorNodeHelper ); + var detailNode = containerNode as DetailGeneratorNode; if( detailNode != null ) { @@ -1547,18 +1383,17 @@ namespace Xceed.Wpf.DataGrid // OPTIMIZATION: We will look in the m_genPos* first to avoid using // FindItem for performance reason. - int index = m_genPosToItem.IndexOf( containerDataItem ); - if( index > -1 ) + var index = m_genPosToItem.IndexOf( containerDataItem ); + if( index >= 0 ) { - int sourceDataIndex = ( int )m_genPosToContainer[ index ].GetValue( DataGridVirtualizingPanel.ItemIndexProperty ); + var sourceDataIndex = ( int )m_genPosToContainer[ index ].GetValue( DataGridVirtualizingPanel.ItemIndexProperty ); containerNode = m_genPosToNode[ index ]; containerRealizedIndex = m_genPosToIndex[ index ]; - CollectionGeneratorNode collectionNode = containerNode as CollectionGeneratorNode; + var collectionNode = containerNode as CollectionGeneratorNode; if( collectionNode != null ) { - nodeHelper = new GeneratorNodeHelper( - containerNode, containerRealizedIndex - collectionNode.IndexOf( containerDataItem ), sourceDataIndex ); + nodeHelper = new GeneratorNodeHelper( containerNode, containerRealizedIndex - collectionNode.IndexOf( containerDataItem ), sourceDataIndex ); } } @@ -1571,7 +1406,7 @@ namespace Xceed.Wpf.DataGrid } if( containerRealizedIndex == -1 ) - throw new DataGridInternalException( "The index of a sticky header container is out of bound.", m_dataGridControl ); + throw DataGridException.Create( "The index of a sticky header container is out of bound.", m_dataGridControl ); generatedStickyContainers.AddRange( this.GenerateStickyHeadersForDetail( container, @@ -1582,7 +1417,7 @@ namespace Xceed.Wpf.DataGrid } else { - CollectionGeneratorNode collectionNode = containerNode as CollectionGeneratorNode; + var collectionNode = containerNode as CollectionGeneratorNode; if( collectionNode != null ) { // We don't need to have an up to date sourceDataIndex so we pass 0 @@ -1606,7 +1441,7 @@ namespace Xceed.Wpf.DataGrid // We want to find the HeaderFooterGeneratorNode for the container // node. This is to find the headers for the container. nodeHelper.MoveToFirst(); - HeadersFootersGeneratorNode headersNode = nodeHelper.CurrentNode as HeadersFootersGeneratorNode; + var headersNode = nodeHelper.CurrentNode as HeadersFootersGeneratorNode; // There is no headers to generate if the item count of the node is 0. if( headersNode.ItemCount > 0 ) @@ -1624,7 +1459,7 @@ namespace Xceed.Wpf.DataGrid // We must also find the top most headers for our level of detail and, if they need to be sticky, // we will generate the containers and add them the to list. - HeadersFootersGeneratorNode topMostHeaderNode = this.GetTopMostHeaderNode( nodeHelper ); + var topMostHeaderNode = this.GetTopMostHeaderNode( nodeHelper ); if( ( areHeadersSticky ) && ( topMostHeaderNode != null ) && ( topMostHeaderNode != headersNode ) @@ -1640,7 +1475,7 @@ namespace Xceed.Wpf.DataGrid private HeadersFootersGeneratorNode GetTopMostHeaderNode( GeneratorNodeHelper nodeHelper ) { - HeadersFootersGeneratorNode parentNode = null; + var parentNode = default( HeadersFootersGeneratorNode ); if( nodeHelper.MoveToParent() && nodeHelper.MoveToFirst() ) @@ -1666,32 +1501,30 @@ namespace Xceed.Wpf.DataGrid bool areGroupHeadersSticky, bool areParentRowsSticky ) { - List generatedStickyContainers = - detailNode.DetailGenerator.GenerateStickyHeaders( container, areHeadersSticky, areGroupHeadersSticky, areParentRowsSticky ); + var generatedStickyContainers = detailNode.DetailGenerator.GenerateStickyHeaders( container, areHeadersSticky, areGroupHeadersSticky, areParentRowsSticky ); + var detailIndex = this.FindGlobalIndexForDetailNode( detailNode ); + var count = generatedStickyContainers.Count; - int detailIndex = this.FindGlobalIndexForDetailNode( detailNode ); - - int count = generatedStickyContainers.Count; for( int i = 0; i < count; i++ ) { - StickyContainerGenerated stickyContainer = generatedStickyContainers[ i ]; - int detailItemIndex = stickyContainer.Index + detailIndex; + var stickyContainer = generatedStickyContainers[ i ]; + var detailItemIndex = stickyContainer.Index + detailIndex; //if the container was just realized, ensure to add it to the lists maintaining the generated items. if( stickyContainer.IsNewlyRealized ) { - int insertionIndex = this.FindInsertionPoint( detailItemIndex ); + var insertionIndex = this.FindInsertionPoint( detailItemIndex ); + var item = CustomItemContainerGenerator.GetDataItemProperty( stickyContainer.StickyContainer ).Data; + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_GenerateStickyHeadersForDetail, DataGridTraceMessages.ContainerAdded, DataGridTraceArgs.Container( stickyContainer.StickyContainer ), DataGridTraceArgs.Node( detailNode ), DataGridTraceArgs.Item( item ), DataGridTraceArgs.GeneratorIndex( insertionIndex ), DataGridTraceArgs.Index( detailItemIndex ) ); m_genPosToIndex.Insert( insertionIndex, detailItemIndex ); - m_genPosToItem.Insert( insertionIndex, CustomItemContainerGenerator.GetDataItemProperty( stickyContainer.StickyContainer ).Data ); + m_genPosToItem.Insert( insertionIndex, item ); m_genPosToContainer.Insert( insertionIndex, stickyContainer.StickyContainer ); m_genPosToNode.Insert( insertionIndex, detailNode ); } - generatedStickyContainers[ i ] = new StickyContainerGenerated( - stickyContainer.StickyContainer, - detailItemIndex, - stickyContainer.IsNewlyRealized ); + generatedStickyContainers[ i ] = new StickyContainerGenerated( stickyContainer.StickyContainer, detailItemIndex, stickyContainer.IsNewlyRealized ); } return generatedStickyContainers; @@ -1699,13 +1532,13 @@ namespace Xceed.Wpf.DataGrid private StickyContainerGenerated GenerateStickyParentRow( int itemNodeIndex ) { - ICustomItemContainerGenerator generator = ( ICustomItemContainerGenerator )this; - GeneratorPosition position = generator.GeneratorPositionFromIndex( itemNodeIndex ); + var generator = ( ICustomItemContainerGenerator )this; + var position = generator.GeneratorPositionFromIndex( itemNodeIndex ); using( generator.StartAt( position, GeneratorDirection.Forward, true ) ) { bool isNewlyRealized; - DependencyObject container = generator.GenerateNext( out isNewlyRealized ); + var container = generator.GenerateNext( out isNewlyRealized ); return new StickyContainerGenerated( container, itemNodeIndex, isNewlyRealized ); } @@ -1724,11 +1557,11 @@ namespace Xceed.Wpf.DataGrid int realizedIndex, bool isRealizedIndexPartOfHeaderNode ) { - List generatedStickyContainers = new List(); + var generatedStickyContainers = new List(); // The container is already part of the header. - ICustomItemContainerGenerator generator = ( ICustomItemContainerGenerator )this; - GeneratorPosition position = generator.GeneratorPositionFromIndex( headerNodeIndex ); + var generator = ( ICustomItemContainerGenerator )this; + var position = generator.GeneratorPositionFromIndex( headerNodeIndex ); // In that case, the potential sticky containers are the requested one and up. using( generator.StartAt( position, GeneratorDirection.Forward, true ) ) @@ -1739,26 +1572,25 @@ namespace Xceed.Wpf.DataGrid // item, do not process if( ( isRealizedIndexPartOfHeaderNode ) && ( headerNodeIndex + i > realizedIndex ) ) - { break; - } - object item = headerNode.GetAt( i ); - - GroupHeaderFooterItem? groupHeaderFooterItem = null; + var item = headerNode.GetAt( i ); + var groupHeaderFooterItem = default( GroupHeaderFooterItem? ); if( item is GroupHeaderFooterItem ) + { groupHeaderFooterItem = ( GroupHeaderFooterItem )item; + } if( ( groupHeaderFooterItem != null ) - && ( !( groupHeaderFooterItem.Value.Group.IsBottomLevel ) || !this.IsGroupExpanded( groupHeaderFooterItem.Value.Group ) ) ) + && ( !groupHeaderFooterItem.Value.Group.IsBottomLevel || ( this.IsGroupExpanded( groupHeaderFooterItem.Value.Group ) != true ) ) ) { this.Skip(); continue; } bool isNewlyRealized; - DependencyObject stickyContainer = generator.GenerateNext( out isNewlyRealized ); + var stickyContainer = generator.GenerateNext( out isNewlyRealized ); generatedStickyContainers.Add( new StickyContainerGenerated( stickyContainer, headerNodeIndex + i, isNewlyRealized ) ); } @@ -1773,9 +1605,8 @@ namespace Xceed.Wpf.DataGrid out int containerRealizedIndex, out object containerDataItem ) { - int index = m_genPosToContainer.IndexOf( container ); - - if( index == -1 ) + var index = m_genPosToContainer.IndexOf( container ); + if( index < 0 ) { containerNode = null; containerRealizedIndex = -1; @@ -1783,12 +1614,14 @@ namespace Xceed.Wpf.DataGrid return false; } + else + { + containerNode = m_genPosToNode[ index ]; + containerRealizedIndex = m_genPosToIndex[ index ]; + containerDataItem = m_genPosToItem[ index ]; - containerNode = m_genPosToNode[ index ]; - containerRealizedIndex = m_genPosToIndex[ index ]; - containerDataItem = m_genPosToItem[ index ]; - - return true; + return true; + } } public int GetLastHoldingContainerIndexForStickyHeader( DependencyObject stickyHeader ) @@ -1798,7 +1631,7 @@ namespace Xceed.Wpf.DataGrid private int GetLastHoldingContainerIndexForStickyHeaderRecurse( DependencyObject stickyHeader, int parentCount ) { - int lastContainerIndex = 0; + var lastContainerIndex = 0; int containerRealizedIndex; GeneratorNode containerNode; @@ -1806,8 +1639,7 @@ namespace Xceed.Wpf.DataGrid if( this.FindGeneratorListMappingInformationForContainer( stickyHeader, out containerNode, out containerRealizedIndex, out containerDataItem ) ) { - DetailGeneratorNode detailNode = containerNode as DetailGeneratorNode; - + var detailNode = containerNode as DetailGeneratorNode; if( detailNode != null ) { lastContainerIndex = @@ -1816,14 +1648,13 @@ namespace Xceed.Wpf.DataGrid } else { - ItemsGeneratorNode itemsNode = containerNode as ItemsGeneratorNode; - + var itemsNode = containerNode as ItemsGeneratorNode; if( itemsNode != null ) { // This means that the sticky container is a MasterRow for a detail. if( this.AreDetailsExpanded( containerDataItem ) ) { - List detailNodesForDataItem = m_masterToDetails[ containerDataItem ]; + var detailNodesForDataItem = m_masterToDetails[ containerDataItem ]; foreach( DetailGeneratorNode detailNodeForDataItem in detailNodesForDataItem ) { @@ -1836,10 +1667,10 @@ namespace Xceed.Wpf.DataGrid } else { - GeneratorNodeHelper nodeHelper = null; + var nodeHelper = default( GeneratorNodeHelper ); // This means that the sticky container is a Header. - CollectionGeneratorNode collectionNode = containerNode as CollectionGeneratorNode; + var collectionNode = containerNode as CollectionGeneratorNode; if( collectionNode != null ) { // We don't need to have an up to date sourceDataIndex so we pass 0 @@ -1872,7 +1703,7 @@ namespace Xceed.Wpf.DataGrid public int GetFirstHoldingContainerIndexForStickyFooter( DependencyObject stickyFooter ) { - int firstContainerIndex = 0; + var firstContainerIndex = 0; int containerRealizedIndex; GeneratorNode containerNode; @@ -1880,7 +1711,7 @@ namespace Xceed.Wpf.DataGrid if( this.FindGeneratorListMappingInformationForContainer( stickyFooter, out containerNode, out containerRealizedIndex, out containerDataItem ) ) { - DetailGeneratorNode detailNode = containerNode as DetailGeneratorNode; + var detailNode = containerNode as DetailGeneratorNode; if( detailNode != null ) { @@ -1889,9 +1720,9 @@ namespace Xceed.Wpf.DataGrid } else { - GeneratorNodeHelper nodeHelper = null; + var nodeHelper = default( GeneratorNodeHelper ); + var collectionNode = containerNode as CollectionGeneratorNode; - CollectionGeneratorNode collectionNode = containerNode as CollectionGeneratorNode; if( collectionNode != null ) { // We don't need to have an up to date sourceDataIndex so we pass 0 @@ -1922,7 +1753,7 @@ namespace Xceed.Wpf.DataGrid bool areFootersSticky, bool areGroupFootersSticky ) { - List generatedStickyContainers = new List(); + var generatedStickyContainers = new List(); GeneratorNode containerNode; int containerRealizedIndex; @@ -1934,8 +1765,8 @@ namespace Xceed.Wpf.DataGrid out containerRealizedIndex, out containerDataItem ) ) { - GeneratorNodeHelper nodeHelper = null; - DetailGeneratorNode detailNode = containerNode as DetailGeneratorNode; + var nodeHelper = default( GeneratorNodeHelper ); + var detailNode = containerNode as DetailGeneratorNode; if( detailNode != null ) { @@ -1948,13 +1779,13 @@ namespace Xceed.Wpf.DataGrid // OPTIMIZATION: We will look in the m_genPos* first to avoid using // FindItem for performance reason. int index = m_genPosToItem.IndexOf( containerDataItem ); - if( index > -1 ) + if( index >= 0 ) { - int sourceDataIndex = ( int )m_genPosToContainer[ index ].GetValue( DataGridVirtualizingPanel.ItemIndexProperty ); + var sourceDataIndex = ( int )m_genPosToContainer[ index ].GetValue( DataGridVirtualizingPanel.ItemIndexProperty ); containerNode = m_genPosToNode[ index ]; containerRealizedIndex = m_genPosToIndex[ index ]; - CollectionGeneratorNode collectionNode = containerNode as CollectionGeneratorNode; + var collectionNode = containerNode as CollectionGeneratorNode; if( collectionNode != null ) { nodeHelper = new GeneratorNodeHelper( containerNode, containerRealizedIndex - collectionNode.IndexOf( containerDataItem ), sourceDataIndex ); @@ -1970,14 +1801,14 @@ namespace Xceed.Wpf.DataGrid } if( containerRealizedIndex == -1 ) - throw new DataGridInternalException( "The index of a sticky footer container is out of bound.", m_dataGridControl ); + throw DataGridException.Create( "The index of a sticky footer container is out of bound.", m_dataGridControl ); generatedStickyContainers.AddRange( this.GenerateStickyFootersForDetail( container, detailNode, areFootersSticky, areGroupFootersSticky ) ); } else { - CollectionGeneratorNode collectionNode = containerNode as CollectionGeneratorNode; + var collectionNode = containerNode as CollectionGeneratorNode; if( collectionNode != null ) { // We don't need to have an up to date sourceDataIndex so we pass 0 @@ -1998,7 +1829,7 @@ namespace Xceed.Wpf.DataGrid // We want to find the HeaderFooterGeneratorNode for the container // node. This is to find the footers for the container. nodeHelper.MoveToEnd(); - HeadersFootersGeneratorNode footersNode = nodeHelper.CurrentNode as HeadersFootersGeneratorNode; + var footersNode = nodeHelper.CurrentNode as HeadersFootersGeneratorNode; if( !isHeaderNode ) { @@ -2019,7 +1850,7 @@ namespace Xceed.Wpf.DataGrid // We must also find the bottom most footers for our level of detail and, if they need to be sticky, // we will generate the containers and add them the to list. - HeadersFootersGeneratorNode bottomFootersNode = this.GetDetailFootersNode( nodeHelper ); + var bottomFootersNode = this.GetDetailFootersNode( nodeHelper ); if( ( areFootersSticky ) && ( bottomFootersNode != null ) @@ -2040,32 +1871,30 @@ namespace Xceed.Wpf.DataGrid bool areFootersSticky, bool areGroupFootersSticky ) { - List generatedStickyContainers = - detailNode.DetailGenerator.GenerateStickyFooters( container, areFootersSticky, areGroupFootersSticky ); + var generatedStickyContainers = detailNode.DetailGenerator.GenerateStickyFooters( container, areFootersSticky, areGroupFootersSticky ); + var detailIndex = this.FindGlobalIndexForDetailNode( detailNode ); + var count = generatedStickyContainers.Count; - int detailIndex = this.FindGlobalIndexForDetailNode( detailNode ); - - int count = generatedStickyContainers.Count; for( int i = 0; i < count; i++ ) { - StickyContainerGenerated stickyContainer = generatedStickyContainers[ i ]; - int detailItemIndex = stickyContainer.Index + detailIndex; + var stickyContainer = generatedStickyContainers[ i ]; + var detailItemIndex = stickyContainer.Index + detailIndex; //if the container was just realized, ensure to add it to the lists maintaining the generated items. if( stickyContainer.IsNewlyRealized ) { - int insertionIndex = this.FindInsertionPoint( detailItemIndex ); + var insertionIndex = this.FindInsertionPoint( detailItemIndex ); + var item = CustomItemContainerGenerator.GetDataItemProperty( stickyContainer.StickyContainer ).Data; + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_GenerateStickyFootersForDetail, DataGridTraceMessages.ContainerAdded, DataGridTraceArgs.Container( stickyContainer.StickyContainer ), DataGridTraceArgs.Node( detailNode ), DataGridTraceArgs.Item( item ), DataGridTraceArgs.GeneratorIndex( insertionIndex ), DataGridTraceArgs.Index( detailItemIndex ) ); m_genPosToIndex.Insert( insertionIndex, detailItemIndex ); - m_genPosToItem.Insert( insertionIndex, CustomItemContainerGenerator.GetDataItemProperty( stickyContainer.StickyContainer ).Data ); + m_genPosToItem.Insert( insertionIndex, item ); m_genPosToContainer.Insert( insertionIndex, stickyContainer.StickyContainer ); m_genPosToNode.Insert( insertionIndex, detailNode ); } - generatedStickyContainers[ i ] = new StickyContainerGenerated( - stickyContainer.StickyContainer, - detailItemIndex, - stickyContainer.IsNewlyRealized ); + generatedStickyContainers[ i ] = new StickyContainerGenerated( stickyContainer.StickyContainer, detailItemIndex, stickyContainer.IsNewlyRealized ); } return generatedStickyContainers; @@ -2084,13 +1913,13 @@ namespace Xceed.Wpf.DataGrid int realizedIndex, bool isRealizedIndexPartOfFooterNode ) { - List generatedStickyContainers = new List(); + var generatedStickyContainers = new List(); int footersNodeItemCount = footerNode.ItemCount; // The container is already part of the footer. - ICustomItemContainerGenerator generator = ( ICustomItemContainerGenerator )this; - GeneratorPosition position = generator.GeneratorPositionFromIndex( footerNodeIndex + footersNodeItemCount - 1 ); + var generator = ( ICustomItemContainerGenerator )this; + var position = generator.GeneratorPositionFromIndex( footerNodeIndex + footersNodeItemCount - 1 ); // In that case, the potential sticky containers are the requested one and bottom. using( generator.StartAt( position, GeneratorDirection.Backward, true ) ) @@ -2103,22 +1932,23 @@ namespace Xceed.Wpf.DataGrid continue; } - object item = footerNode.GetAt( i ); - - GroupHeaderFooterItem? groupHeaderFooterItem = null; + var item = footerNode.GetAt( i ); + var groupHeaderFooterItem = default( GroupHeaderFooterItem? ); if( item is GroupHeaderFooterItem ) + { groupHeaderFooterItem = ( GroupHeaderFooterItem )item; + } if( ( groupHeaderFooterItem != null ) - && ( !( groupHeaderFooterItem.Value.Group.IsBottomLevel ) || !this.IsGroupExpanded( groupHeaderFooterItem.Value.Group ) ) ) + && ( !groupHeaderFooterItem.Value.Group.IsBottomLevel || ( this.IsGroupExpanded( groupHeaderFooterItem.Value.Group ) != true ) ) ) { this.Skip(); continue; } bool isNewlyRealized; - DependencyObject stickyContainer = generator.GenerateNext( out isNewlyRealized ); + var stickyContainer = generator.GenerateNext( out isNewlyRealized ); generatedStickyContainers.Add( new StickyContainerGenerated( stickyContainer, footerNodeIndex + i, isNewlyRealized ) ); } @@ -2129,7 +1959,7 @@ namespace Xceed.Wpf.DataGrid private HeadersFootersGeneratorNode GetDetailFootersNode( GeneratorNodeHelper nodeHelper ) { - HeadersFootersGeneratorNode parentNode = null; + var parentNode = default( HeadersFootersGeneratorNode ); if( nodeHelper.MoveToParent() && nodeHelper.MoveToEnd() ) @@ -2158,26 +1988,20 @@ namespace Xceed.Wpf.DataGrid bool areGroupHeadersSticky, bool areParentRowsSticky ) { - int stickyHeadersCount = 0; - - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + var stickyHeadersCount = 0; + var nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + // Unable to find the node, no sticky header for this node if( !nodeHelper.FindNodeForIndex( index ) ) - { - // Unable to find the node, no sticky header for this node return 0; - } - GeneratorNode indexNode = nodeHelper.CurrentNode; - - ItemsGeneratorNode itemsGeneratorNode = indexNode as ItemsGeneratorNode; + var indexNode = nodeHelper.CurrentNode; + var itemsGeneratorNode = indexNode as ItemsGeneratorNode; // We found an ItemsGeneratorNode if( itemsGeneratorNode != null ) { - GeneratorNode innerNode = itemsGeneratorNode.GetDetailNodeForIndex( index - nodeHelper.Index ); - - DetailGeneratorNode detailNode = innerNode as DetailGeneratorNode; + var detailNode = itemsGeneratorNode.GetDetailNodeForIndex( index - nodeHelper.Index ); // Only do a special case if the index represent // a DetailNode @@ -2189,10 +2013,10 @@ namespace Xceed.Wpf.DataGrid stickyHeadersCount++; } - int detailFirstRealizedIndex = this.FindGlobalIndexForDetailNode( detailNode ); - int correctedIndex = index - detailFirstRealizedIndex; + var detailFirstRealizedIndex = this.FindGlobalIndexForDetailNode( detailNode ); + var correctedIndex = index - detailFirstRealizedIndex; - m_log.Assert( this, correctedIndex >= 0, "correctedIndex >= 0 .. 1" ); + Debug.Assert( correctedIndex >= 0, "correctedIndex >= 0 .. 1" ); stickyHeadersCount += detailNode.DetailGenerator.GetStickyHeaderCountForIndex( correctedIndex, @@ -2202,11 +2026,10 @@ namespace Xceed.Wpf.DataGrid } } - // We want to find the HeaderFooterGeneratorNode for the container // node. This is to find the headers for the container. nodeHelper.MoveToFirst(); - HeadersFootersGeneratorNode headersNode = nodeHelper.CurrentNode as HeadersFootersGeneratorNode; + var headersNode = nodeHelper.CurrentNode as HeadersFootersGeneratorNode; // There is no headers to generate if the item count of the node is 0. if( headersNode.ItemCount > 0 ) @@ -2225,7 +2048,7 @@ namespace Xceed.Wpf.DataGrid // We must also find the top most headers for our level of detail and, if they need to be sticky, // we will generate the containers and add them the to list. - HeadersFootersGeneratorNode topMostHeaderNode = this.GetTopMostHeaderNode( nodeHelper ); + var topMostHeaderNode = this.GetTopMostHeaderNode( nodeHelper ); if( ( topMostHeaderNode != null ) && ( topMostHeaderNode != headersNode ) && ( topMostHeaderNode.ItemCount > 0 ) @@ -2234,7 +2057,6 @@ namespace Xceed.Wpf.DataGrid stickyHeadersCount += this.GetStickyHeaderCountForNode( topMostHeaderNode, nodeHelper.Index ); } - return stickyHeadersCount; } @@ -2249,28 +2071,25 @@ namespace Xceed.Wpf.DataGrid int realizedIndex, bool isRealizedIndexPartOfHeaderNode ) { - int stickyHeaderCount = 0; + var stickyHeaderCount = 0; for( int i = 0; i < headerNode.ItemCount; i++ ) { if( ( isRealizedIndexPartOfHeaderNode ) && ( headerNodeIndex + i >= realizedIndex ) ) - { break; - } - object item = headerNode.GetAt( i ); - - GroupHeaderFooterItem? groupHeaderFooterItem = null; + var item = headerNode.GetAt( i ); + var groupHeaderFooterItem = default( GroupHeaderFooterItem? ); if( item is GroupHeaderFooterItem ) + { groupHeaderFooterItem = ( GroupHeaderFooterItem )item; + } if( ( groupHeaderFooterItem != null ) - && ( !( groupHeaderFooterItem.Value.Group.IsBottomLevel ) || !this.IsGroupExpanded( groupHeaderFooterItem.Value.Group ) ) ) - { + && ( !groupHeaderFooterItem.Value.Group.IsBottomLevel || ( this.IsGroupExpanded( groupHeaderFooterItem.Value.Group ) != true ) ) ) continue; - } stickyHeaderCount++; } @@ -2287,33 +2106,26 @@ namespace Xceed.Wpf.DataGrid bool areFootersSticky, bool areGroupFootersSticky ) { - int stickyFooterCount = 0; - - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + var stickyFooterCount = 0; + var nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + // Unable to find the node, no sticky header for this node if( !nodeHelper.FindNodeForIndex( index ) ) - { - // Unable to find the node, no sticky header for this node return 0; - } - GeneratorNode indexNode = nodeHelper.CurrentNode; - - ItemsGeneratorNode itemsGeneratorNode = indexNode as ItemsGeneratorNode; + var indexNode = nodeHelper.CurrentNode; + var itemsGeneratorNode = indexNode as ItemsGeneratorNode; // We found an ItemsGeneratorNode if( itemsGeneratorNode != null ) { - GeneratorNode innerNode = itemsGeneratorNode.GetDetailNodeForIndex( index - nodeHelper.Index ); - - DetailGeneratorNode detailNode = innerNode as DetailGeneratorNode; - + var detailNode = itemsGeneratorNode.GetDetailNodeForIndex( index - nodeHelper.Index ); if( detailNode != null ) { - int detailFirstRealizedIndex = this.FindGlobalIndexForDetailNode( detailNode ); - int correctedIndex = index - detailFirstRealizedIndex; + var detailFirstRealizedIndex = this.FindGlobalIndexForDetailNode( detailNode ); + var correctedIndex = index - detailFirstRealizedIndex; - m_log.Assert( this, correctedIndex >= 0, "correctedIndex >= 0 .. 2" ); + Debug.Assert( correctedIndex >= 0, "correctedIndex >= 0 .. 2" ); stickyFooterCount += detailNode.DetailGenerator.GetStickyFooterCountForIndex( correctedIndex, @@ -2325,7 +2137,7 @@ namespace Xceed.Wpf.DataGrid // We want to find the HeaderFooterGeneratorNode for the container // node. This is to find the footers for the container. nodeHelper.MoveToEnd(); - HeadersFootersGeneratorNode footersNode = nodeHelper.CurrentNode as HeadersFootersGeneratorNode; + var footersNode = nodeHelper.CurrentNode as HeadersFootersGeneratorNode; // There is no footers to generate if the item count of the node is 0. if( footersNode.ItemCount > 0 ) @@ -2344,7 +2156,7 @@ namespace Xceed.Wpf.DataGrid // We must also find the bottom most footers for our level of detail and, if they need to be sticky, // we will generate the containers and add them the to list. - HeadersFootersGeneratorNode bottomFootersNode = this.GetDetailFootersNode( nodeHelper ); + var bottomFootersNode = this.GetDetailFootersNode( nodeHelper ); if( ( bottomFootersNode != null ) && ( bottomFootersNode != footersNode ) @@ -2370,29 +2182,26 @@ namespace Xceed.Wpf.DataGrid int realizedIndex, bool isRealizedIndexPartOfHeaderNode ) { - int stickyFooterCount = 0; + var stickyFooterCount = 0; + var footersNodeItemCount = footerNode.ItemCount; - int footersNodeItemCount = footerNode.ItemCount; for( int i = footersNodeItemCount - 1; i >= 0; i-- ) { if( ( isRealizedIndexPartOfHeaderNode ) && ( footerNodeIndex + i < realizedIndex ) ) - { continue; - } - object item = footerNode.GetAt( i ); - - GroupHeaderFooterItem? groupHeaderFooterItem = null; + var item = footerNode.GetAt( i ); + var groupHeaderFooterItem = default( GroupHeaderFooterItem? ); if( item is GroupHeaderFooterItem ) + { groupHeaderFooterItem = ( GroupHeaderFooterItem )item; + } if( ( groupHeaderFooterItem != null ) - && ( !( groupHeaderFooterItem.Value.Group.IsBottomLevel ) || !this.IsGroupExpanded( groupHeaderFooterItem.Value.Group ) ) ) - { + && ( !groupHeaderFooterItem.Value.Group.IsBottomLevel || ( this.IsGroupExpanded( groupHeaderFooterItem.Value.Group ) != true ) ) ) continue; - } stickyFooterCount++; } @@ -2407,126 +2216,127 @@ namespace Xceed.Wpf.DataGrid DependencyObject IItemContainerGenerator.GenerateNext( out bool isNewlyRealized ) { if( this.Status != GeneratorStatus.GeneratingContainers ) - DataGridException.ThrowSystemException( "The Generator is not active: StartAt() was not called prior calling GenerateNext() or the returned IDisposable was already disposed of.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "The Generator is not active: StartAt() was not called prior calling GenerateNext() or the returned IDisposable was already disposed of.", m_dataGridControl ); - DependencyObject container = null; isNewlyRealized = false; - if( m_generatorNodeHelper == null ) //the m_generatorNodeHelper will be turned to null when we reach the end of the list ot items. - return null; + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_IItemContainerGenerator_GenerateNext ) ) + { + if( m_generatorNodeHelper == null ) //the m_generatorNodeHelper will be turned to null when we reach the end of the list ot items. + return null; - m_log.Assert( this, !( m_generatorNodeHelper.CurrentNode is GroupGeneratorNode ), "Algorithm should not allow the Generator's m_generatorNodeHelper to be on a GroupGeneratorNode" ); + var node = m_generatorNodeHelper.CurrentNode; + if( node == null ) + throw DataGridException.Create( "CurrentNode is null.", m_dataGridControl ); - GeneratorNode node = m_generatorNodeHelper.CurrentNode; + if( !( node is CollectionGeneratorNode ) ) + throw DataGridException.Create( "CurrentNode is not a CollectionGeneratorNode.", m_dataGridControl ); - if( node == null ) - throw new DataGridInternalException( "CurrentNode is null.", m_dataGridControl ); + if( node is GroupGeneratorNode ) + { + this.TraceEvent( TraceEventType.Error, DataGridTraceEventId.CustomItemContainerGenerator_IItemContainerGenerator_GenerateNext, DataGridTraceMessages.UnexpectedNode, DataGridTraceArgs.Node( node ) ); + } - if( !( node is CollectionGeneratorNode ) ) - throw new DataGridInternalException( "CurrentNode is not a CollectionGeneratorNode.", m_dataGridControl ); + var container = default( DependencyObject ); - //if a detail generator is currently "started", then rely on it for the generation of items - if( m_generatorCurrentDetail != null ) - { - //if the detail generator was not yet started - if( m_generatorCurrentDetailDisposable == null ) + //if a detail generator is currently "started", then rely on it for the generation of items + if( m_generatorCurrentDetail != null ) { - //start it - m_generatorCurrentDetailDisposable = ( ( IItemContainerGenerator )m_generatorCurrentDetail.DetailGenerator ).StartAt( m_generatorCurrentDetail.DetailGenerator.GeneratorPositionFromIndex( m_generatorCurrentDetailIndex ), m_generatorDirection, true ); + //if the detail generator was not yet started + if( m_generatorCurrentDetailDisposable == null ) + { + //start it + m_generatorCurrentDetailDisposable = ( ( IItemContainerGenerator )m_generatorCurrentDetail.DetailGenerator ).StartAt( m_generatorCurrentDetail.DetailGenerator.GeneratorPositionFromIndex( m_generatorCurrentDetailIndex ), m_generatorDirection, true ); + } + + container = ( ( IItemContainerGenerator )m_generatorCurrentDetail.DetailGenerator ).GenerateNext( out isNewlyRealized ); + node = m_generatorCurrentDetail; + //Detail Generator will have taken care of the "nasty" stuff ( ItemIndex, ... ) } + else + { + //otherwise, it means the item to be generated is within this generator. + container = this.GenerateNextLocalContainer( out isNewlyRealized ); - container = ( ( IItemContainerGenerator )m_generatorCurrentDetail.DetailGenerator ).GenerateNext( out isNewlyRealized ); - node = m_generatorCurrentDetail; - //Detail Generator will have taken care of the "nasty" stuff ( ItemIndex, ... ) - } - else - { - //otherwise, it means the item to be generated is within this generator. - container = this.GenerateNextLocalContainer( out isNewlyRealized ); + //special case for table view grid lines + Xceed.Wpf.DataGrid.Views.ViewBase.SetIsLastItem( container, this.ShouldDrawBottomLine() ); + DataGridControl.SetHasExpandedDetails( container, this.ItemHasExpandedDetails() ); + } - //special case for table view grid lines - Xceed.Wpf.DataGrid.Views.ViewBase.SetIsLastItem( container, this.ShouldDrawBottomLine() ); - DataGridControl.SetHasExpandedDetails( container, this.ItemHasExpandedDetails() ); - } + //if the container was just realized, ensure to add it to the lists maintaining the generated items. + if( isNewlyRealized ) + { + var insertionIndex = this.FindInsertionPoint( m_generatorCurrentGlobalIndex ); + var item = CustomItemContainerGenerator.GetDataItemProperty( container ).Data; - //if the container was just realized, ensure to add it to the lists maintaining the generated items. - if( isNewlyRealized ) - { - Debug.Indent(); - int insertionIndex = this.FindInsertionPoint( m_generatorCurrentGlobalIndex ); - Debug.Unindent(); + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_IItemContainerGenerator_GenerateNext, DataGridTraceMessages.ContainerAdded, DataGridTraceArgs.Container( container ), DataGridTraceArgs.Node( node ), DataGridTraceArgs.Item( item ), DataGridTraceArgs.GeneratorIndex( insertionIndex ), DataGridTraceArgs.Index( m_generatorCurrentGlobalIndex ) ); - m_genPosToIndex.Insert( insertionIndex, m_generatorCurrentGlobalIndex ); - m_genPosToItem.Insert( insertionIndex, CustomItemContainerGenerator.GetDataItemProperty( container ).Data ); - m_genPosToContainer.Insert( insertionIndex, container ); - m_genPosToNode.Insert( insertionIndex, node ); + if( insertionIndex > 0 ) + { + if( m_generatorCurrentGlobalIndex <= m_genPosToIndex[ insertionIndex - 1 ] ) + throw DataGridException.Create( "Realized item inserted at wrong location.", m_dataGridControl ); + } + else if( m_genPosToIndex.Count > 0 ) + { + if( m_generatorCurrentGlobalIndex >= m_genPosToIndex[ insertionIndex ] ) + throw DataGridException.Create( "Realized item inserted at wrong location.", m_dataGridControl ); + } - this.ValidateIndexOrder( "genpos" + insertionIndex.ToString() + ", globalIndex" + m_generatorCurrentGlobalIndex.ToString() + ")" ); - } + m_genPosToIndex.Insert( insertionIndex, m_generatorCurrentGlobalIndex ); + m_genPosToItem.Insert( insertionIndex, item ); + m_genPosToContainer.Insert( insertionIndex, container ); + m_genPosToNode.Insert( insertionIndex, node ); + } - if( m_generatorDirection == GeneratorDirection.Forward ) - { - this.MoveGeneratorForward(); - } - else - { - this.MoveGeneratorBackward(); - } + if( m_generatorDirection == GeneratorDirection.Forward ) + { + this.MoveGeneratorForward(); + } + else + { + this.MoveGeneratorBackward(); + } - return container; + return container; + } } DependencyObject IItemContainerGenerator.GenerateNext() { - IItemContainerGenerator generatorInterface = this; bool flag; - return generatorInterface.GenerateNext( out flag ); + + return ( ( IItemContainerGenerator )this ).GenerateNext( out flag ); } public GeneratorPosition GeneratorPositionFromIndex( int itemIndex ) { this.EnsureNodeTreeCreated(); - int genPosIndex = m_genPosToIndex.IndexOf( itemIndex ); - //if the Index maps to a Generated item, then return the GeneratorPosition (easy) - if( genPosIndex != -1 ) - { + var genPosIndex = m_genPosToIndex.IndexOf( itemIndex ); + if( genPosIndex >= 0 ) return new GeneratorPosition( genPosIndex, 0 ); - } - else - { - //If not generated - int storedIndex = -1; - int offset = itemIndex + 1; - //Find the closest (lower) realized index - for( int i = 0; i < m_genPosToIndex.Count; i++ ) - { - storedIndex = i; - if( m_genPosToIndex[ i ] > itemIndex ) - { - storedIndex = i - 1; - break; - } - } + var storedIndex = -1; + var offset = itemIndex + 1; - //and from there, compute the offset. - if( storedIndex >= 0 ) + //Find the closest (lower) realized index + for( int i = 0; i < m_genPosToIndex.Count; i++ ) + { + storedIndex = i; + if( m_genPosToIndex[ i ] > itemIndex ) { - offset = itemIndex - m_genPosToIndex[ storedIndex ]; + storedIndex = i - 1; + break; } - - return new GeneratorPosition( storedIndex, offset ); } - } - private GeneratorPosition GetSafeGeneratorPositionFromIndex( int itemIndex ) - { - using( this.DeferDetailsRemap() ) + //and from there, compute the offset. + if( storedIndex >= 0 ) { - return this.GeneratorPositionFromIndex( itemIndex ); + offset = itemIndex - m_genPosToIndex[ storedIndex ]; } + + return new GeneratorPosition( storedIndex, offset ); } ItemContainerGenerator IItemContainerGenerator.GetItemContainerGeneratorForPanel( Panel panel ) @@ -2534,11 +2344,6 @@ namespace Xceed.Wpf.DataGrid return ( ( IItemContainerGenerator )( ( ItemsControl )m_dataGridControl ).ItemContainerGenerator ).GetItemContainerGeneratorForPanel( panel ); } - /// - /// - /// - /// - /// The index returned is the GlobalRealizedIndex public int IndexFromGeneratorPosition( GeneratorPosition position ) { this.EnsureNodeTreeCreated(); @@ -2568,8 +2373,7 @@ namespace Xceed.Wpf.DataGrid void IItemContainerGenerator.PrepareItemContainer( DependencyObject container ) { if( this.Status != GeneratorStatus.GeneratingContainers ) - DataGridException.ThrowSystemException( "The Generator is not active: StartAt() was not called prior calling PrepareItemContainer() or the returned IDisposable was already disposed of.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "The Generator is not active: StartAt() was not called prior calling PrepareItemContainer() or the returned IDisposable was already disposed of.", m_dataGridControl ); var dataItemStore = CustomItemContainerGenerator.GetDataItemProperty( container ); if( ( dataItemStore == null ) || dataItemStore.IsEmpty ) @@ -2585,49 +2389,41 @@ namespace Xceed.Wpf.DataGrid void IItemContainerGenerator.Remove( GeneratorPosition position, int count ) { if( this.Status == GeneratorStatus.GeneratingContainers ) - DataGridException.ThrowSystemException( "Cannot perform this operation while the generator is busy generating items", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "Cannot perform this operation while the generator is busy generating items", m_dataGridControl ); if( position.Offset != 0 ) - DataGridException.ThrowSystemException( "The GeneratorPosition to remove cannot map to a non-realized item.", typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "The GeneratorPosition to remove cannot map to a non-realized item.", m_dataGridControl, "position" ); if( position.Index == -1 ) - DataGridException.ThrowSystemException( "he GeneratorPosition to remove cannot map to a non-realized item.", typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "The GeneratorPosition to remove cannot map to a non-realized item.", m_dataGridControl, "position" ); + + if( count <= 0 ) + throw DataGridException.Create( "The number of item to remove must be greater than or equal to one.", m_dataGridControl, "count" ); - //if the index passed is within the array! - if( position.Index < m_genPosToIndex.Count ) + if( position.Index >= m_genPosToIndex.Count ) + throw DataGridException.Create( "Trying to remove an item at an out-of-bound GeneratorPosition index", m_dataGridControl ); + + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_IItemContainerGenerator_Remove, DataGridTraceArgs.Index( position.Index ), DataGridTraceArgs.Count( count ) ) ) { - //remove the items requested. for( int i = 0; i < count; i++ ) { if( this.RemoveGeneratedItem( position.Index, null ) == 0 ) //This case deserves a more solid approach... We do not want to allow removal from the user panel of an item that somehow is not present. - throw new DataGridInternalException( "Trying to remove an item at an out-of-bound GenratorPosition index.", m_dataGridControl ); + throw DataGridException.Create( "Trying to remove an item at an out-of-bound GeneratorPosition index.", m_dataGridControl ); } - - //No need to update the Generator current generation, since the content of the generator items did not change (only the list of realized items). - //m_currentGeneratorContentGeneration++; - } - else - { - throw new DataGridInternalException( "Trying to remove an item at an out-of-bound GenratorPosition index", m_dataGridControl ); } - } void IItemContainerGenerator.RemoveAll() { if( this.Status == GeneratorStatus.GeneratingContainers ) - DataGridException.ThrowSystemException( "Cannot perform this operation while the generator is busy generating items", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "Cannot perform this operation while the generator is busy generating items", m_dataGridControl ); using( this.SetIsHandlingGlobalItemsResetLocally() ) { //Call to remove all shall not request container recycling panels to remove their containers. Therefore, I am not collecting the remove containers. this.RemoveAllGeneratedItems(); } - - //No need to update the Generator current generation, since the content of the generator items did not change (only the list of realized items). } IDisposable IItemContainerGenerator.StartAt( GeneratorPosition position, GeneratorDirection direction, bool allowStartAtRealizedItem ) @@ -2635,8 +2431,7 @@ namespace Xceed.Wpf.DataGrid this.SetIsInUse(); if( this.Status == GeneratorStatus.GeneratingContainers ) - DataGridException.ThrowSystemException( "Cannot perform this operation while the generator is busy generating items", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "Cannot perform this operation while the generator is busy generating items", m_dataGridControl ); this.EnsureNodeTreeCreated(); @@ -2676,7 +2471,7 @@ namespace Xceed.Wpf.DataGrid //then re-evaluate the number of items. if( m_startNode != null ) { - // If it does that correctly, then this function is OK. + // If it does that correctly, then this function is OK. int chainLength; GeneratorNodeHelper.EvaluateChain( m_startNode, out m_cachedItemCount, out chainLength ); } @@ -2701,14 +2496,13 @@ namespace Xceed.Wpf.DataGrid } set { - //if the container recylcing is turned OFF from ON + //if the container recycling is turned OFF from ON if( value == ( bool )m_flags[ ( int )CustomItemContainerGeneratorFlags.RecyclingEnabled ] ) return; if( !value ) { - //clear the container queues - m_dataGridContext.RecyclingManager.Clear(); + this.ClearRecyclingPools(); } m_flags[ ( int )CustomItemContainerGeneratorFlags.RecyclingEnabled ] = value; @@ -2738,25 +2532,23 @@ namespace Xceed.Wpf.DataGrid // DataGridControl. This is required for scenarios such as the CardflowItemsHost. this.EnsureNodeTreeCreated(); - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + var nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); //First, locate the item within the Generator. object newCurrentItem = nodeHelper.FindIndex( newCurrentIndex ); if( newCurrentItem == null ) - DataGridException.ThrowSystemException( "An attempt was made to access an item at an index that does not correspond to an item.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "An attempt was made to access an item at an index that does not correspond to an item.", m_dataGridControl ); //Then, if the item is within an ItemsNode, check if it belongs to a detail - ItemsGeneratorNode itemsNode = nodeHelper.CurrentNode as ItemsGeneratorNode; + var itemsNode = nodeHelper.CurrentNode as ItemsGeneratorNode; if( itemsNode != null ) { int masterIndex; int detailIndex; int detailNodeIndex; - DetailGeneratorNode detailNode = itemsNode.GetDetailNodeForIndex( newCurrentIndex - nodeHelper.Index, out masterIndex, out detailIndex, out detailNodeIndex ); - //If it belongs to a detail + var detailNode = itemsNode.GetDetailNodeForIndex( newCurrentIndex - nodeHelper.Index, out masterIndex, out detailIndex, out detailNodeIndex ); if( detailNode != null ) { //call recursively the SetCurrentIndex method on the detail generator to ensure that if the item @@ -2774,23 +2566,20 @@ namespace Xceed.Wpf.DataGrid int ICustomItemContainerGenerator.GetCurrentIndex() { - int index = -1; if( m_dataGridControl.CurrentContext != null ) - { - index = this.FindIndexForItem( m_dataGridControl.CurrentContext.InternalCurrentItem, m_dataGridContext ); - } + return this.FindIndexForItem( m_dataGridControl.CurrentContext.InternalCurrentItem, m_dataGridContext ); - return index; + return -1; } void ICustomItemContainerGenerator.RestoreFocus( DependencyObject container ) { if( !m_genPosToContainer.Contains( container ) ) - DataGridException.ThrowSystemException( "The specified container is not part of the generator's content.", - typeof( ArgumentException ), m_dataGridControl.Name, "container" ); + throw DataGridException.Create( "The specified container is not part of the generator's content.", m_dataGridControl, "container" ); + + var dataGridContext = DataGridControl.GetDataGridContext( container ); + var column = ( dataGridContext == null ) ? null : dataGridContext.CurrentColumn; - DataGridContext dataGridContext = DataGridControl.GetDataGridContext( container ); - ColumnBase column = ( dataGridContext == null ) ? null : dataGridContext.CurrentColumn; m_dataGridControl.SetFocusHelper( container as UIElement, column, false, true ); } @@ -2798,38 +2587,38 @@ namespace Xceed.Wpf.DataGrid private DependencyObject GenerateNextLocalContainer( out bool isNewlyRealized ) { - DependencyObject container = null; - object dataItem; - CollectionGeneratorNode node = m_generatorNodeHelper.CurrentNode as CollectionGeneratorNode; + var container = default( DependencyObject ); + var node = m_generatorNodeHelper.CurrentNode as CollectionGeneratorNode; - m_log.Assert( this, node != null, "CustomItemContainerGenerator.GenerateNextLocalContainer: node is null." ); + //if the index exists in the list, then the item is already realized. + var genPosIndex = m_genPosToIndex.IndexOf( m_generatorCurrentGlobalIndex ); + var itemsNode = node as ItemsGeneratorNode; - ItemsGeneratorNode itemsNode = node as ItemsGeneratorNode; + if( node == null ) + { + this.TraceEvent( TraceEventType.Error, DataGridTraceEventId.CustomItemContainerGenerator_GenerateNextLocalContainer, DataGridTraceMessages.UnexpectedNode, DataGridTraceArgs.Node( node ), DataGridTraceArgs.GeneratorIndex( genPosIndex ) ); + } - //if the index exists in the list, then the item is already realized. - int genPosIndex = m_genPosToIndex.IndexOf( m_generatorCurrentGlobalIndex ); + object dataItem; - if( genPosIndex != -1 ) + if( genPosIndex >= 0 ) { //retrieve the container for the item that is already stored in the data structure container = m_genPosToContainer[ genPosIndex ]; dataItem = m_genPosToItem[ genPosIndex ]; - GeneratorNode tempNode = m_genPosToNode[ genPosIndex ]; + + var tempNode = m_genPosToNode[ genPosIndex ]; node = tempNode as CollectionGeneratorNode; if( tempNode == null ) { - this.LogState(); - m_log.Fail( this, "CustomItemContainerGenerator.GenerateNextLocalContainer: ### cached Node is null ( at " + genPosIndex.ToString() + " )" ); - - throw new DataGridInternalException( "CustomItemContainerGenerator.GenerateNextLocalContainer: cached Node is null", m_dataGridControl ); + this.TraceEvent( TraceEventType.Critical, DataGridTraceEventId.CustomItemContainerGenerator_GenerateNextLocalContainer, DataGridTraceMessages.UnexpectedNode, DataGridTraceArgs.Node( node ), DataGridTraceArgs.GeneratorIndex( genPosIndex ), DataGridTraceArgs.Container( container ), DataGridTraceArgs.Item( dataItem ) ); + throw DataGridException.Create( "CustomItemContainerGenerator.GenerateNextLocalContainer: cached Node is null", m_dataGridControl ); } else if( node != m_generatorNodeHelper.CurrentNode ) { - this.LogState(); - m_log.Fail( this, "CustomItemContainerGenerator.GenerateNextLocalContainer: # testNode is not the current one. ( " + m_genPosToNode[ genPosIndex ].GetType().ToString() + " ) ( at " + genPosIndex.ToString() + " )" ); - - throw new DataGridInternalException( "CustomItemContainerGenerator.GenerateNextLocalContainer: Node is not the current one.", m_dataGridControl ); + this.TraceEvent( TraceEventType.Critical, DataGridTraceEventId.CustomItemContainerGenerator_GenerateNextLocalContainer, DataGridTraceMessages.NodeIsNotTheCurrentNode, DataGridTraceArgs.Node( tempNode ), DataGridTraceArgs.Node( m_generatorNodeHelper.CurrentNode ), DataGridTraceArgs.GeneratorIndex( genPosIndex ), DataGridTraceArgs.Container( container ), DataGridTraceArgs.Item( dataItem ) ); + throw DataGridException.Create( "CustomItemContainerGenerator.GenerateNextLocalContainer: Node is not the current one.", m_dataGridControl ); } isNewlyRealized = false; @@ -2863,12 +2652,11 @@ namespace Xceed.Wpf.DataGrid { int itemIndex = m_generatorNodeHelper.SourceDataIndex + m_generatorCurrentOffset; - //this section is used to ensure that the Item Index is properly attached to all containers DataGridVirtualizingPanel.SetItemIndex( container, itemIndex ); - SelectionRange currentSelection = new SelectionRange( itemIndex ); - - DataRow rowToSelect = container as DataRow; + //In order to make sure the container is properly selected, a new selection range must be initialized with the updated item index. + var currentSelection = new SelectionRange( itemIndex ); + var rowToSelect = container as DataRow; if( rowToSelect != null ) { @@ -2890,8 +2678,9 @@ namespace Xceed.Wpf.DataGrid if( node != null ) { //determine the appropriate GroupConfiguration ( based on parent node ) and set it on the container. - GroupConfiguration groupConfig = null; - GroupGeneratorNode parentNode = node.Parent as GroupGeneratorNode; //implicit rule: a parent node is always a GroupGeneratorNode + var groupConfig = default( GroupConfiguration ); + var parentNode = node.Parent as GroupGeneratorNode; //implicit rule: a parent node is always a GroupGeneratorNode + if( parentNode != null ) { groupConfig = parentNode.GroupConfiguration; @@ -2902,69 +2691,91 @@ namespace Xceed.Wpf.DataGrid DataGridControl.SetContainerGroupConfiguration( container, groupConfig ); } } - else - { - this.LogState(); - m_log.Fail( this, "CustomItemContainerGenerator.GenerateNextLocalContainer: node is null ( at " + genPosIndex.ToString() + " )" ); - } + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_GenerateNextLocalContainer, DataGridTraceMessages.ContainerGenerated, DataGridTraceArgs.Container( container ), DataGridTraceArgs.Node( node ), DataGridTraceArgs.GeneratorIndex( genPosIndex ), DataGridTraceArgs.Value( isNewlyRealized ) ); return container; } - private void UpdateDataVirtualizationLockForItemsNode( ItemsGeneratorNode itemsNode, object dataItem, bool applyLock ) + private bool IsDataVirtualized( ItemsGeneratorNode node ) { - IList items = itemsNode.Items; + DataGridVirtualizingCollectionViewBase collectionView; + VirtualList items; - ItemCollection itemCollection = items as ItemCollection; + return this.TryGetVirtualizedCollection( node, out collectionView, out items ); + } - if( itemCollection != null ) + private bool TryGetVirtualizedCollection( ItemsGeneratorNode node, out DataGridVirtualizingCollectionViewBase collectionView, out VirtualList items ) + { + if( node == null ) { - DataGridVirtualizingCollectionViewBase dataGridVirtualizingCollectionViewBase = - itemCollection.SourceCollection as DataGridVirtualizingCollectionViewBase; - - if( dataGridVirtualizingCollectionViewBase != null ) - { - int index = itemsNode.Items.IndexOf( dataItem ); - if( applyLock ) - { - dataGridVirtualizingCollectionViewBase.RootGroup.LockGlobalIndex( index ); - } - else - { - dataGridVirtualizingCollectionViewBase.RootGroup.UnlockGlobalIndex( index ); - } - } + collectionView = default( DataGridVirtualizingCollectionViewBase ); + items = default( VirtualList ); } else { - VirtualList virtualItemList = items as VirtualList; - - if( virtualItemList != null ) + var itemCollection = node.Items as ItemCollection; + if( itemCollection != null ) { - int index = itemsNode.Items.IndexOf( dataItem ); - - if( applyLock ) - { - virtualItemList.LockPageForLocalIndex( index ); - } - else - { - virtualItemList.UnlockPageForLocalIndex( index ); - } + collectionView = itemCollection.SourceCollection as DataGridVirtualizingCollectionViewBase; + items = default( VirtualList ); + } + else + { + collectionView = default( DataGridVirtualizingCollectionViewBase ); + items = node.Items as VirtualList; } } + return ( collectionView != null ) + || ( items != null ); + } + + private void UpdateDataVirtualizationLockForItemsNode( ItemsGeneratorNode node, object dataItem, bool applyLock ) + { + DataGridVirtualizingCollectionViewBase collectionView; + VirtualList items; + + if( !this.TryGetVirtualizedCollection( node, out collectionView, out items ) ) + return; + + if( collectionView != null ) + { + var index = node.Items.IndexOf( dataItem ); + if( applyLock ) + { + collectionView.RootGroup.LockGlobalIndex( index ); + } + else + { + collectionView.RootGroup.UnlockGlobalIndex( index ); + } + } + else if( items != null ) + { + var index = node.Items.IndexOf( dataItem ); + if( applyLock ) + { + items.LockPageForLocalIndex( index ); + } + else + { + items.UnlockPageForLocalIndex( index ); + } + } } private void MoveGeneratorForward() { - ItemsGeneratorNode currentMasterNode = m_generatorNodeHelper.CurrentNode as ItemsGeneratorNode; + var currentMasterNode = m_generatorNodeHelper.CurrentNode as ItemsGeneratorNode; //if I was generating from a detail generator if( m_generatorCurrentDetail != null ) { - m_log.Assert( this, currentMasterNode != null, "CustomItemContainerGenerator.MoveGeneratorForward: currentMasterNode is not null." ); - m_log.Assert( this, currentMasterNode.Details != null, "CustomItemContainerGenerator.MoveGeneratorForward: currentMasterNode.Details is not null." ); + if( ( currentMasterNode == null ) || ( currentMasterNode.Details == null ) ) + { + this.TraceEvent( TraceEventType.Critical, DataGridTraceEventId.CustomItemContainerGenerator_MoveGeneratorForward, DataGridTraceMessages.UnexpectedNode, DataGridTraceArgs.Node( currentMasterNode ) ); + } //incremment the running counter for the item index generated in the detail generator m_generatorCurrentDetailIndex++; @@ -2983,7 +2794,10 @@ namespace Xceed.Wpf.DataGrid List detailsforMasterNode; currentMasterNode.Details.TryGetValue( m_generatorCurrentOffset, out detailsforMasterNode ); - m_log.Assert( this, detailsforMasterNode != null, "CustomItemContainerGenerator.MoveGeneratorForward: detailsforMasterNode is not null." ); + if( detailsforMasterNode == null ) + { + this.TraceEvent( TraceEventType.Critical, DataGridTraceEventId.CustomItemContainerGenerator_MoveGeneratorForward, DataGridTraceMessages.DetailExpected, DataGridTraceArgs.Node( currentMasterNode ) ); + } while( ( m_generatorCurrentDetailNodeIndex < detailsforMasterNode.Count ) && ( m_generatorCurrentDetailIndex == -1 ) ) { @@ -3019,11 +2833,11 @@ namespace Xceed.Wpf.DataGrid if( ( currentMasterNode != null ) && ( currentMasterNode.Details != null ) && ( currentMasterNode.Details.TryGetValue( m_generatorCurrentOffset, out detailsForNode ) ) ) { - bool foundDetail = false; + var foundDetail = false; for( int i = 0; i < detailsForNode.Count; i++ ) { - DetailGeneratorNode detailNode = detailsForNode[ i ]; + var detailNode = detailsForNode[ i ]; if( detailNode.ItemCount > 0 ) { @@ -3069,13 +2883,15 @@ namespace Xceed.Wpf.DataGrid private void MoveGeneratorBackward() { - ItemsGeneratorNode currentMasterNode = m_generatorNodeHelper.CurrentNode as ItemsGeneratorNode; + var currentMasterNode = m_generatorNodeHelper.CurrentNode as ItemsGeneratorNode; //if I was generating from a detail generator if( m_generatorCurrentDetail != null ) { - m_log.Assert( this, currentMasterNode != null, "CustomItemContainerGenerator.MoveGeneratorBackward: currentMasterNode is not null." ); - m_log.Assert( this, currentMasterNode.Details != null, "CustomItemContainerGenerator.MoveGeneratorBackward: currentMasterNode.Details is not null." ); + if( ( currentMasterNode == null ) || ( currentMasterNode.Details == null ) ) + { + this.TraceEvent( TraceEventType.Critical, DataGridTraceEventId.CustomItemContainerGenerator_MoveGeneratorBackward, DataGridTraceMessages.UnexpectedNode, DataGridTraceArgs.Node( currentMasterNode ) ); + } //decrement the running counter for the item index generated in the detail generator m_generatorCurrentDetailIndex--; @@ -3096,7 +2912,10 @@ namespace Xceed.Wpf.DataGrid List detailsforMasterNode; currentMasterNode.Details.TryGetValue( m_generatorCurrentOffset, out detailsforMasterNode ); - m_log.Assert( this, detailsforMasterNode != null, "CustomItemContainerGenerator.MoveGeneratorBackward: detailsforMasterNode is not null." ); + if( detailsforMasterNode == null ) + { + this.TraceEvent( TraceEventType.Critical, DataGridTraceEventId.CustomItemContainerGenerator_MoveGeneratorBackward, DataGridTraceMessages.DetailExpected, DataGridTraceArgs.Node( currentMasterNode ) ); + } while( ( m_generatorCurrentDetailNodeIndex >= 0 ) && ( m_generatorCurrentDetailIndex == -1 ) ) { @@ -3161,20 +2980,17 @@ namespace Xceed.Wpf.DataGrid } m_generatorCurrentGlobalIndex--; - } private void SetupLastDetailForNode( ItemsGeneratorNode node ) { List detailsForNode; - if( ( node != null ) && ( node.Details != null ) - && ( node.Details.TryGetValue( m_generatorCurrentOffset, out detailsForNode ) ) ) + if( ( node != null ) && ( node.Details != null ) && ( node.Details.TryGetValue( m_generatorCurrentOffset, out detailsForNode ) ) ) { for( int i = detailsForNode.Count - 1; i >= 0; i-- ) { - DetailGeneratorNode detailNode = detailsForNode[ i ]; - + var detailNode = detailsForNode[ i ]; if( detailNode.ItemCount > 0 ) { //There are details for the master item @@ -3190,8 +3006,7 @@ namespace Xceed.Wpf.DataGrid private bool ShouldDrawBottomLine() { if( m_generatorStatus != GeneratorStatus.GeneratingContainers ) - DataGridException.ThrowSystemException( "An attempt was made to call the CustomItemContainerGenerator.ShouldDrawBottomLine method while containers are not being generated.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "An attempt was made to call the CustomItemContainerGenerator.ShouldDrawBottomLine method while containers are not being generated.", m_dataGridControl ); return ( m_generatorCurrentGlobalIndex == ( this.ItemCount - 1 ) ); } @@ -3199,10 +3014,9 @@ namespace Xceed.Wpf.DataGrid private bool ItemHasExpandedDetails() { if( m_generatorStatus != GeneratorStatus.GeneratingContainers ) - DataGridException.ThrowSystemException( "An attempt was made to call the CustomItemContainerGenerator.ItemHasExpandedDetails method while containers are not being generated.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "An attempt was made to call the CustomItemContainerGenerator.ItemHasExpandedDetails method while containers are not being generated.", m_dataGridControl ); - ItemsGeneratorNode itemsNode = m_generatorNodeHelper.CurrentNode as ItemsGeneratorNode; + var itemsNode = m_generatorNodeHelper.CurrentNode as ItemsGeneratorNode; if( ( itemsNode == null ) || ( itemsNode.Details == null ) ) return false; @@ -3216,71 +3030,60 @@ namespace Xceed.Wpf.DataGrid internal void CleanupGenerator( bool isNestedCall ) { - m_log.Assert( this, !this.IsHandlingGlobalItemsResetLocally, "Generator is already processing a HandleGlobalItemReset or CleanupGenerator" ); - - if( this.IsHandlingGlobalItemsResetLocally ) - return; - - using( m_log.BeginBlock( this, null ) ) - using( this.SetIsHandlingGlobalItemsResetLocally() ) + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_CleanupGenerator ) ) { - this.RemoveAllGeneratedItems(); + this.ForceReset = false; - IList removedContainers = null; - - var recyclingManager = m_dataGridContext.RecyclingManager; - recyclingManager.RemoveRef( this ); - if( recyclingManager.RefCount == 0 ) + if( this.IsHandlingGlobalItemsResetLocally ) { - removedContainers = m_dataGridContext.RecyclingManager.Clear(); + this.TraceEvent( TraceEventType.Warning, DataGridTraceEventId.CustomItemContainerGenerator_CleanupGenerator, DataGridTraceMessages.CannotProcessOnReset ); + return; } - if( !isNestedCall ) + using( this.SetIsHandlingGlobalItemsResetLocally() ) { - this.SendResetEvent(); - } + this.RemoveAllGeneratedItems(); - //This call needs not to be defered or moved... effectivelly, the reset has already occured in that case... - if( ( removedContainers != null ) && ( removedContainers.Count > 0 ) ) - { - this.NotifyContainersRemoved( removedContainers ); - } + if( !isNestedCall ) + { + this.SendResetEvent(); + this.ClearRecyclingPools(); + } - this.ClearLateGroupLevelDescriptions(); + this.ClearLateGroupLevelDescriptions(); - if( m_startNode != null ) - { - //Note: this does not disconnects the "general" master/detail relationship established between an Item and its details, - //within the Generator itself, however, it does break the link between the GeneratorNode where the details are mapped. - this.NodeFactory.CleanGeneratorNodeTree( m_startNode ); - } + if( m_startNode != null ) + { + //Note: this does not disconnects the "general" master/detail relationship established between an Item and its details, + //within the Generator itself, however, it does break the link between the GeneratorNode where the details are mapped. + this.NodeFactory.CleanGeneratorNodeTree( m_startNode ); + } - m_groupNodeMappingCache.Clear(); - m_firstHeader = null; - m_firstFooter = null; - m_firstItem = null; - m_startNode = null; + m_groupNodeMappingCache.Clear(); + m_firstHeader = null; + m_firstFooter = null; + m_firstItem = null; + m_startNode = null; - //This absolutelly needs to be done after the node list is Cleaned! - this.CleanupDetailRelations(); + //This absolutelly needs to be done after the node list is Cleaned! + this.CleanupDetailRelations(); + this.InvalidateNodeTree(); + } } } private void CleanupDetailRelations() { - using( m_log.BeginBlock( this, null ) ) - { - var detailNodes = this.GetDetailGeneratorNodes().ToList(); - - m_masterToDetails.Clear(); + var detailNodes = this.GetDetailGeneratorNodes().ToList(); - foreach( var detailNode in detailNodes ) - { - this.ClearDetailGeneratorNode( detailNode ); - } + m_masterToDetails.Clear(); - m_floatingDetails.Clear(); + foreach( var detailNode in detailNodes ) + { + this.ClearDetailGeneratorNode( detailNode ); } + + m_floatingDetails.Clear(); } private void IncrementCurrentGenerationCount( bool updateGenPosList ) @@ -3320,27 +3123,57 @@ namespace Xceed.Wpf.DataGrid private void OnDetailConfigurationsChanged( object sender, NotifyCollectionChangedEventArgs e ) { - switch( e.Action ) + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_OnDetailConfigurationsChanged ) ) { - case NotifyCollectionChangedAction.Remove: - { - break; - } + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_OnDetailConfigurationsChanged, DataGridTraceArgs.Action( e.Action ) ); - case NotifyCollectionChangedAction.Move: - case NotifyCollectionChangedAction.Add: - case NotifyCollectionChangedAction.Replace: - case NotifyCollectionChangedAction.Reset: - default: - { - using( m_log.BeginBlock( this, "DetailConfiguration Changed" ) ) + switch( e.Action ) + { + case NotifyCollectionChangedAction.Remove: + { + using( m_recyclingPools.DeferContainersRemoved() ) + { + foreach( DetailConfiguration detailConfiguration in e.OldItems ) + { + this.CloseDetails( detailConfiguration ); + + m_recyclingPools.Clear( detailConfiguration ); + } + } + break; + } + + case NotifyCollectionChangedAction.Move: + case NotifyCollectionChangedAction.Add: + case NotifyCollectionChangedAction.Replace: + case NotifyCollectionChangedAction.Reset: + default: { // That ensure the RemapFloatingDetails() got called and the loop on m_masterToDetails.Keys will not contain invalid item. this.EnsureNodeTreeCreated(); + + foreach( object item in m_masterToDetails.Keys.ToList() ) + { + this.CloseDetailsForItem( item, null ); + } + break; } + } + } + } - break; - } + private void OnCollectionViewPropertyChanged( PropertyChangedEventArgs e ) + { + var propertyName = e.PropertyName; + + if( string.IsNullOrEmpty( propertyName ) || ( propertyName == DataGridCollectionViewBase.GroupsPropertyName ) ) + { + this.OnCollectionViewGroupsPropertyChanged(); + } + + if( string.IsNullOrEmpty( propertyName ) || ( propertyName == DataGridCollectionViewBase.RootGroupPropertyName ) ) + { + this.OnCollectionViewRootGroupChanged(); } } @@ -3352,362 +3185,342 @@ namespace Xceed.Wpf.DataGrid this.HandleGlobalItemsReset(); } - private void OnItemsChanged( object sender, NotifyCollectionChangedEventArgs e ) + private void OnCollectionViewRootGroupChanged() { - // Avoid re-entrance when processing a global reset - if( this.IsHandlingGlobalItemsResetLocally ) - return; - - if( this.Status == GeneratorStatus.GeneratingContainers ) - DataGridException.ThrowSystemException( "Cannot perform this operation while the generator is busy generating items.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); - - switch( e.Action ) + for( int i = 0; i < m_genPosToNode.Count; i++ ) { - case NotifyCollectionChangedAction.Add: - //do not handle the Items.CollectionChanged if groups are present or if there is already a items node. - // (because the OnGeneratorNodeItemsCollectionChanged will handle things) - if( m_collectionView.GroupDescriptions.Count == 0 ) - { - if( m_firstItem == null ) - { + if( !( m_genPosToNode[ i ] is HeadersFootersGeneratorNode ) ) + continue; - int addCount = e.NewItems.Count; - GeneratorPosition genPos = new GeneratorPosition( -1, 1 ); + this.SetStatContext( m_genPosToContainer[ i ], m_genPosToNode[ i ] ); + } + } - this.IncrementCurrentGenerationCount(); + private void OnItemsChanged( object sender, NotifyCollectionChangedEventArgs e ) + { + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_OnItemsChanged ) ) + { + if( this.IsHandlingGlobalItemsResetLocally ) + { + this.TraceEvent( TraceEventType.Warning, DataGridTraceEventId.CustomItemContainerGenerator_OnItemsChanged, DataGridTraceMessages.CannotProcessOnReset, DataGridTraceArgs.Action( e.Action ) ); + return; + } - this.SendAddEvent( genPos, 0, addCount ); - } - } - break; + if( this.Status == GeneratorStatus.GeneratingContainers ) + throw DataGridException.Create( "Cannot perform this operation while the generator is busy generating items.", m_dataGridControl ); - case NotifyCollectionChangedAction.Move: - case NotifyCollectionChangedAction.Remove: - case NotifyCollectionChangedAction.Replace: - //I voluntarilly do not handle these particular cases because the ItemsNode - //handler will cover it. (OnGeneratorNodeItemsCollectionChanged) - break; + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_OnItemsChanged, DataGridTraceArgs.Action( e.Action ) ); - case NotifyCollectionChangedAction.Reset: - if( ( m_groupsCollection == null ) || ( m_collectionView.GroupDescriptions.Count == 0 ) ) + if( this.ForceReset ) + { + this.HandleGlobalItemsReset(); + } + else + { + if( e.Action == NotifyCollectionChangedAction.Reset ) { - this.HandleGlobalItemsReset(); + if( ( m_groupsCollection == null ) != ( m_collectionView.GroupDescriptions.Count == 0 ) ) + { + this.HandleGlobalItemsReset(); + } } - - break; + } } } private void OnGroupsChanged( object sender, NotifyCollectionChangedEventArgs e ) { - // Avoid re-entrance when processing a global reset - if( this.IsHandlingGlobalItemsResetLocally ) - return; + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_OnGroupsChanged, DataGridTraceArgs.Group( sender ) ) ) + { + if( this.IsHandlingGlobalItemsResetLocally ) + { + this.TraceEvent( TraceEventType.Warning, DataGridTraceEventId.CustomItemContainerGenerator_OnGroupsChanged, DataGridTraceMessages.CannotProcessOnReset, DataGridTraceArgs.Group( sender ), DataGridTraceArgs.Action( e.Action ) ); + return; + } - if( this.Status == GeneratorStatus.GeneratingContainers ) - DataGridException.ThrowSystemException( "Cannot perform this operation while the generator is busy generating items.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + if( this.Status == GeneratorStatus.GeneratingContainers ) + throw DataGridException.Create( "Cannot perform this operation while the generator is busy generating items.", m_dataGridControl ); - //this fonction is only used to process the content of the DataGridControl.Items.Groups collection... - // for the CollectionChanged event of branch groups ( IsBottomLevel = false ), refer to the - // OnBranchGroupsChanged fonction + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_OnGroupsChanged, DataGridTraceArgs.Group( sender ), DataGridTraceArgs.Action( e.Action ) ); - switch( e.Action ) - { - case NotifyCollectionChangedAction.Add: - int addCount = e.NewItems.Count; + switch( e.Action ) + { + case NotifyCollectionChangedAction.Add: + { + var count = e.NewItems.Count; + + //if the first item is empty, do not do anything, the structure will be generated when the generator is started! + if( m_firstItem != null ) + { + //The only moment where the m_firstItem is null is typically when a reset occured... + //other moments is when there are 0 items. + this.HandleSameLevelGroupAddition( m_firstItem, out count, e ); + this.IncrementCurrentGenerationCount(); + } - GeneratorPosition genPos = new GeneratorPosition( -1, 1 ); //this would map to the first item in the list if not generated. + this.SendAddEvent( count ); + } + break; - int addIndex = -1; + case NotifyCollectionChangedAction.Move: + { + if( m_firstItem != null ) + { + if( !( m_firstItem is GroupGeneratorNode ) ) + throw DataGridException.Create( "Trying to move a GeneratorNode that is not a GroupGeneratorNode.", m_dataGridControl ); - //if the first item is empty, do not do anything, the structure will be generated when the generator is started! - if( m_firstItem != null ) - { - //The only moment where the m_firstItem is null is typically when a reset occured... - //other moments is when there are 0 items (in which case, the. + Debug.Assert( e.OldStartingIndex != e.NewStartingIndex, "An attempt was made to move a group to the same location." ); - GeneratorNode addNode = this.HandleSameLevelGroupAddition( m_firstItem, out addCount, e ); + this.HandleSameLevelGroupMove( m_firstItem, e ); + } + } + break; - this.IncrementCurrentGenerationCount(); + case NotifyCollectionChangedAction.Remove: + { + if( m_firstItem != null ) + { + if( !( m_firstItem is GroupGeneratorNode ) ) + throw DataGridException.Create( "Trying to remove a GeneratorNode that is not a GroupGeneratorNode.", m_dataGridControl ); - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( addNode, 0, 0 );//index not important, will reserve find it. - nodeHelper.ReverseCalculateIndex(); - addIndex = nodeHelper.Index; + var count = default( int ); + var containers = new List(); - genPos = this.GeneratorPositionFromIndex( addIndex ); - } + this.HandleSameLevelGroupRemove( m_firstItem, out count, e, containers ); + this.IncrementCurrentGenerationCount(); + this.SendRemoveEvent( count, containers ); + } + } + break; - this.SendAddEvent( genPos, addIndex, addCount ); + case NotifyCollectionChangedAction.Replace: + throw DataGridException.Create( "Replace not supported at the moment on groups.", m_dataGridControl ); - break; + case NotifyCollectionChangedAction.Reset: + { + if( m_firstItem != null ) + { + if( !( m_firstItem is GroupGeneratorNode ) ) + throw DataGridException.Create( "Trying to reset a GeneratorNode that is not a GroupGeneratorNode.", m_dataGridControl ); - case NotifyCollectionChangedAction.Move: - if( m_firstItem != null ) - { - if( !( m_firstItem is GroupGeneratorNode ) ) - throw new DataGridInternalException( "Trying to move a GeneratorNode that is not a GroupGeneratorNode.", m_dataGridControl ); + this.HandleSameLevelGroupReset( m_firstItem ); + } + else + { + this.HandleGlobalItemsReset(); + } + } + break; + } + } + } - m_log.Assert( this, e.OldStartingIndex != e.NewStartingIndex, "An attempt was made to move a group to the same location." ); + private void OnGeneratorNodeItemsCollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) + { + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_OnGeneratorNodeItemsCollectionChanged, DataGridTraceArgs.Node( sender ), DataGridTraceArgs.Action( e.Action ) ) ) + { + if( this.IsHandlingGlobalItemsResetLocally ) + { + this.TraceEvent( TraceEventType.Warning, DataGridTraceEventId.CustomItemContainerGenerator_OnGeneratorNodeItemsCollectionChanged, DataGridTraceMessages.CannotProcessOnReset, DataGridTraceArgs.Node( sender ), DataGridTraceArgs.Action( e.Action ) ); + return; + } - this.HandleSameLevelGroupMove( m_firstItem, e ); - } - break; + if( this.Status == GeneratorStatus.GeneratingContainers ) + throw DataGridException.Create( "Cannot perform this operation while the generator is busy generating items.", m_dataGridControl ); - case NotifyCollectionChangedAction.Remove: - if( m_firstItem != null ) - { - if( !( m_firstItem is GroupGeneratorNode ) ) - throw new DataGridInternalException( "Trying to remove a GeneratorNode that is not a GroupGeneratorNode.", m_dataGridControl ); + var node = ( ItemsGeneratorNode )sender; + var updateContainersIndex = !node.IsComputedExpanded; - int remCount; - int generatedRemCount; - int removeIndex; - List removedContainers = new List(); - GeneratorPosition remPos = this.HandleSameLevelGroupRemove( m_firstItem, out remCount, out generatedRemCount, out removeIndex, e, removedContainers ); + e = e.GetRangeActionOrSelf(); - //there is no need to check if the parent node is expanded or not... since the first level of group cannot be collapsed. + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_OnGeneratorNodeItemsCollectionChanged, DataGridTraceArgs.Node( sender ), DataGridTraceArgs.Action( e.Action ) ); - this.IncrementCurrentGenerationCount(); + switch( e.Action ) + { + case NotifyCollectionChangedAction.Add: + { + this.HandleItemAddition( node, e ); + } + break; - this.SendRemoveEvent( remPos, removeIndex, remCount, generatedRemCount, removedContainers ); - } + case NotifyCollectionChangedAction.Remove: + { + this.HandleItemRemoveMoveReplace( node, e ); + } + break; - break; + case NotifyCollectionChangedAction.Move: + case NotifyCollectionChangedAction.Replace: + { + //detect the case where the replace is targeted at a single item, replaced with himself. + //This particular case is there to handle the particularities of the DGCV with regards to + //IBindingList.ListChanged.ChangeType == ItemChanged. + if( ( e.Action == NotifyCollectionChangedAction.Replace ) && + ( e.OldItems.Count == 1 ) && ( e.NewItems.Count == 1 ) && + ( e.NewItems[ 0 ] == e.OldItems[ 0 ] ) ) + { + // Getting a replace with the same instance should just do nothing. + // + // Note : We know that will prevent a row from refreshing correctly if the item + // are not implementing a mechanic of notification ( like INotifyPropertyChanged ). - case NotifyCollectionChangedAction.Replace: - DataGridException.ThrowSystemException( "Replace not supported at the moment on groups.", typeof( NotSupportedException ), m_dataGridControl.Name ); - break; + updateContainersIndex = false; + } + else + { + //any other case, normal handling + this.HandleItemRemoveMoveReplace( node, e ); + } + } + break; - case NotifyCollectionChangedAction.Reset: - if( m_firstItem != null ) - { - if( !( m_firstItem is GroupGeneratorNode ) ) - throw new DataGridInternalException( "Trying to reset a GeneratorNode that is not a GroupGeneratorNode.", m_dataGridControl ); + case NotifyCollectionChangedAction.Reset: + { + this.HandleItemReset( node ); + } + break; + } - this.HandleSameLevelGroupReset( m_firstItem ); - } - else - { - this.HandleGlobalItemsReset(); - } - break; + if( updateContainersIndex ) + { + this.UpdateContainersIndex(); + } } - } - private void OnGeneratorNodeItemsCollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) + private void OnGeneratorNodeExpansionStateChanged( object sender, ExpansionStateChangedEventArgs e ) { - // Avoid re-entrance when processing a global reset - if( this.IsHandlingGlobalItemsResetLocally ) - return; - if( this.Status == GeneratorStatus.GeneratingContainers ) - DataGridException.ThrowSystemException( "Cannot perform this operation while the generator is busy generating items.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "Cannot perform this operation while the generator is busy generating items.", m_dataGridControl ); - var node = sender as GeneratorNode; - if( node == null ) - return; + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_OnGeneratorNodeExpansionStateChanged, DataGridTraceArgs.Node( sender ) ) ) + { - var itemsNode = sender as ItemsGeneratorNode; - var headersNode = sender as HeadersFootersGeneratorNode; + var node = sender as GeneratorNode; + Debug.Assert( node != null ); - e = e.GetRangeActionOrSelf(); + var changedNode = node.Parent as GroupGeneratorNode; + if( changedNode == null ) + { + this.TraceEvent( TraceEventType.Error, DataGridTraceEventId.CustomItemContainerGenerator_OnGeneratorNodeExpansionStateChanged, DataGridTraceMessages.UnexpectedNode, DataGridTraceArgs.Node( node.Parent ) ); + } - switch( e.Action ) - { - case NotifyCollectionChangedAction.Add: - this.HandleItemAddition( node, e ); - break; - - case NotifyCollectionChangedAction.Remove: - if( itemsNode != null ) - { - this.HandleItemRemoveMoveReplace( itemsNode, e ); - } - else if( headersNode != null ) - { - this.HandleHeaderFooterRemove( headersNode, e ); - } - else - { - throw new DataGridInternalException( "Cannot remove the GeneratorNode as it is not of a valid type.", m_dataGridControl ); - } - break; - - case NotifyCollectionChangedAction.Move: - case NotifyCollectionChangedAction.Replace: - if( itemsNode != null ) - { - //detect the case where the replace is targeted at a single item, replaced with himself. - //This particular case is there to handle the particularities of the DGCV with regards to - //IBindingList.ListChanged.ChangeType == ItemChanged. - if( ( e.Action == NotifyCollectionChangedAction.Replace ) && - ( e.OldItems.Count == 1 ) && ( e.NewItems.Count == 1 ) && - ( e.NewItems[ 0 ] == e.OldItems[ 0 ] ) ) - { - // Getting a replace with the same instance should just do nothing. - // - // Note : We know that will prevent a row from refreshing correctly if the item - // are not implementing a mechanic of notification ( like INotifyPropertyChanged ). - } - else - { - //any other case, normal handling - this.HandleItemRemoveMoveReplace( itemsNode, e ); - } - } - else if( headersNode != null ) - { - this.HandleHeaderFooterReplace( headersNode, e ); - } - else - { - throw new DataGridInternalException( "Cannot move or replace the GeneratorNode as it is not of a valid type.", m_dataGridControl ); - } - break; - - case NotifyCollectionChangedAction.Reset: - this.HandleItemReset( node ); - break; - } - } - - private void OnGeneratorNodeExpansionStateChanged( object sender, ExpansionStateChangedEventArgs e ) - { - //throw an error is the Generator is actually busy generating! - if( this.Status == GeneratorStatus.GeneratingContainers ) - DataGridException.ThrowSystemException( "Cannot perform this operation while the generator is busy generating items.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); - - GeneratorNode node = sender as GeneratorNode; - - m_log.Assert( this, node != null, "node != null" ); - - if( node == null ) - return; - - GroupGeneratorNode changedNode = node.Parent as GroupGeneratorNode; - - m_log.Assert( this, changedNode != null, "changedNode != null" ); //should never be null, as the "node" is supposed to be the child node of this one. - - //Determine if the changedNode is "below" a collapsed group (because if so, I don't need any sort of notification or removal ). - GroupGeneratorNode parentGroupNode = changedNode.Parent as GroupGeneratorNode; - if( ( parentGroupNode != null ) && ( !parentGroupNode.IsComputedExpanded ) ) - return; - - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( node, 0, 0 ); - nodeHelper.ReverseCalculateIndex(); - - //if the node was "Collapsed" - if( !e.NewExpansionState ) - { - int removeCount = e.Count; - int startIndex = nodeHelper.Index + e.IndexOffset; - - GeneratorPosition removeGenPos = this.GeneratorPositionFromIndex( startIndex ); + //Determine if the changedNode is "below" a collapsed group (because if so, I don't need any sort of notification or removal ). + var parentGroupNode = changedNode.Parent as GroupGeneratorNode; + if( ( parentGroupNode != null ) && ( !parentGroupNode.IsComputedExpanded ) ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_OnGeneratorNodeExpansionStateChanged, DataGridTraceMessages.NodeIsCollapsed, DataGridTraceArgs.Node( node ) ); + return; + } - List removedContainers = new List(); - //remove the Generated items between the appropriate indexes - int removeUICount = this.RemoveGeneratedItems( startIndex, startIndex + removeCount - 1, removedContainers ); + var nodeHelper = new GeneratorNodeHelper( node, 0, 0 ); + nodeHelper.ReverseCalculateIndex(); - if( removeCount > 0 ) + //if the node was "Collapsed" + if( !e.NewExpansionState ) { - //send the event so the panel can remove the group elements - this.SendRemoveEvent( removeGenPos, startIndex, removeCount, removeUICount, removedContainers ); - } - } - //if the node was "Expanded" - else - { - int addCount = e.Count; - int startIndex = nodeHelper.Index + e.IndexOffset; - GeneratorPosition addGenPos = this.GeneratorPositionFromIndex( startIndex ); + var startIndex = nodeHelper.Index + e.IndexOffset; + var containers = new List(); - if( addCount > 0 ) + this.RemoveGeneratedItems( startIndex, startIndex + e.Count - 1, containers ); + this.SendRemoveEvent( e.Count, containers ); + } + //if the node was "Expanded" + else { - //send the event so the panel can add the group elements - this.SendAddEvent( addGenPos, startIndex, addCount ); + this.SendAddEvent( e.Count ); } } } private void OnGroupGeneratorNodeIsExpandedChanging( object sender, EventArgs e ) { - //throw an error is the Generator is actually busy generating! if( this.Status == GeneratorStatus.GeneratingContainers ) - DataGridException.ThrowSystemException( "Cannot perform this operation while the generator is busy generating items.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "Cannot perform this operation while the generator is busy generating items.", m_dataGridControl ); + + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_OnGroupGeneratorNodeIsExpandedChanging, DataGridTraceArgs.Node( sender ) ) ) + { + if( m_currentGenPosToIndexInhibiterDisposable != null ) + { + this.TraceEvent( TraceEventType.Error, DataGridTraceEventId.CustomItemContainerGenerator_OnGroupGeneratorNodeIsExpandedChanging, DataGridTraceMessages.InhibiterAlreadySet ); + } - m_log.Assert( this, m_currentGenPosToIndexInhibiterDisposable == null, "m_currentGenPosToIndexInhibiterDisposable == null" ); + m_currentGenPosToIndexInhibiterDisposable = this.InhibitParentGenPosToIndexUpdate(); - m_currentGenPosToIndexInhibiterDisposable = this.InhibitParentGenPosToIndexUpdate(); + var groupGeneratorNode = sender as GroupGeneratorNode; - GroupGeneratorNode groupGeneratorNode = sender as GroupGeneratorNode; - if( ( m_dataGridContext != null ) - && ( !m_dataGridContext.IsDeferRestoringState ) - && ( !m_dataGridContext.IsRestoringState ) - && ( m_dataGridControl != null ) - && ( groupGeneratorNode != null ) - && ( groupGeneratorNode.IsExpanded ) ) - { - TableflowViewItemsHost tableflowItemsHost = m_dataGridControl.ItemsHost as TableflowViewItemsHost; - if( tableflowItemsHost != null ) + if( ( m_dataGridContext != null ) + && ( !m_dataGridContext.IsDeferRestoringState ) + && ( !m_dataGridContext.IsRestoringState ) + && ( m_dataGridControl != null ) + && ( groupGeneratorNode != null ) + && ( groupGeneratorNode.IsExpanded ) ) { - tableflowItemsHost.OnGroupCollapsing( groupGeneratorNode.UIGroup ); + var tableflowItemsHost = m_dataGridControl.ItemsHost as TableflowViewItemsHost; + if( tableflowItemsHost != null ) + { + tableflowItemsHost.OnGroupCollapsing( groupGeneratorNode.UIGroup ); + } } } } private void OnGroupGeneratorNodeIsExpandedChanged( object sender, EventArgs e ) { - //throw an error is the Generator is actually busy generating! if( this.Status == GeneratorStatus.GeneratingContainers ) - DataGridException.ThrowSystemException( "Cannot perform this operation while the generator is busy generating items.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "Cannot perform this operation while the generator is busy generating items.", m_dataGridControl ); - GroupGeneratorNode node = sender as GroupGeneratorNode; - if( node != null ) + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_OnGroupGeneratorNodeIsExpandedChanged, DataGridTraceArgs.Node( sender ) ) ) { - this.IncrementCurrentGenerationCount(); - } + var node = sender as GroupGeneratorNode; + if( node != null ) + { + this.IncrementCurrentGenerationCount(); + } + else + { + this.TraceEvent( TraceEventType.Error, DataGridTraceEventId.CustomItemContainerGenerator_OnGroupGeneratorNodeIsExpandedChanged, DataGridTraceMessages.UnexpectedNode, DataGridTraceArgs.Node( sender ) ); + } - if( m_currentGenPosToIndexInhibiterDisposable != null ) - { - m_currentGenPosToIndexInhibiterDisposable.Dispose(); - m_currentGenPosToIndexInhibiterDisposable = null; + if( m_currentGenPosToIndexInhibiterDisposable != null ) + { + m_currentGenPosToIndexInhibiterDisposable.Dispose(); + m_currentGenPosToIndexInhibiterDisposable = null; + } } } private void OnGeneratorNodeGroupsCollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) { if( this.Status == GeneratorStatus.GeneratingContainers ) - DataGridException.ThrowSystemException( "Cannot perform this operation while the generator is busy generating items.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); - - GroupGeneratorNode node = sender as GroupGeneratorNode; + throw DataGridException.Create( "Cannot perform this operation while the generator is busy generating items.", m_dataGridControl ); - if( node != null ) + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_OnGeneratorNodeGroupsCollectionChanged, DataGridTraceArgs.Node( sender ), DataGridTraceArgs.Action( e.Action ) ) ) { + var node = sender as GroupGeneratorNode; + if( node == null ) + { + this.TraceEvent( TraceEventType.Error, DataGridTraceEventId.CustomItemContainerGenerator_OnGeneratorNodeGroupsCollectionChanged, DataGridTraceMessages.UnexpectedNode, DataGridTraceArgs.Node( sender ), DataGridTraceArgs.Action( e.Action ) ); + return; + } + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_OnGeneratorNodeGroupsCollectionChanged, DataGridTraceArgs.Node( sender ), DataGridTraceArgs.Action( e.Action ) ); + switch( e.Action ) { case NotifyCollectionChangedAction.Add: { - int addCount; - GeneratorNode addNode = this.HandleParentGroupAddition( node, out addCount, e ); + var count = default( int ); + this.HandleParentGroupAddition( node, out count, e ); if( node.IsComputedExpanded ) { - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( addNode, 0, 0 );//index not important, will reserve find it. - nodeHelper.ReverseCalculateIndex(); - this.IncrementCurrentGenerationCount(); - - GeneratorPosition genPos = this.GeneratorPositionFromIndex( nodeHelper.Index ); - - this.SendAddEvent( genPos, nodeHelper.Index, addCount ); + this.SendAddEvent( count ); + } + else + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_OnGeneratorNodeGroupsCollectionChanged, DataGridTraceMessages.NodeIsCollapsed, DataGridTraceArgs.Node( node ) ); } } break; @@ -3715,9 +3528,9 @@ namespace Xceed.Wpf.DataGrid case NotifyCollectionChangedAction.Move: { if( node.Child == null ) - throw new DataGridInternalException( "An attempt was made to move a group with a null child GeneratorNode.", m_dataGridControl ); + throw DataGridException.Create( "An attempt was made to move a group with a null child GeneratorNode.", m_dataGridControl ); - m_log.Assert( this, e.OldStartingIndex != e.NewStartingIndex, "An attempt was made to move a group to the same location." ); + Debug.Assert( e.OldStartingIndex != e.NewStartingIndex, "An attempt was made to move a group to the same location." ); this.HandleSameLevelGroupMove( node.Child, e ); } @@ -3726,31 +3539,32 @@ namespace Xceed.Wpf.DataGrid case NotifyCollectionChangedAction.Remove: { if( node.Child == null ) - throw new DataGridInternalException( "An attempt was made to remove a group with a null child GeneratorNode.", m_dataGridControl ); + throw DataGridException.Create( "An attempt was made to remove a group with a null child GeneratorNode.", m_dataGridControl ); - int remCount; - int generatedRemCount; - int removeIndex; - List removedContainers = new List(); - GeneratorPosition remPos = this.HandleParentGroupRemove( node, out remCount, out generatedRemCount, out removeIndex, e, removedContainers ); + var count = default( int ); + var containers = new List(); + + this.HandleParentGroupRemove( node, out count, e, containers ); if( node.IsComputedExpanded ) { this.IncrementCurrentGenerationCount(); - - this.SendRemoveEvent( remPos, removeIndex, remCount, generatedRemCount, removedContainers ); + this.SendRemoveEvent( count, containers ); + } + else + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_OnGeneratorNodeGroupsCollectionChanged, DataGridTraceMessages.NodeIsCollapsed, DataGridTraceArgs.Node( node ) ); } } break; case NotifyCollectionChangedAction.Replace: - DataGridException.ThrowSystemException( "Replace not supported at the moment on groups.", typeof( NotSupportedException ), m_dataGridControl.Name ); - break; + throw DataGridException.Create( "Replace not supported at the moment on groups.", m_dataGridControl ); case NotifyCollectionChangedAction.Reset: { if( node.Child == null ) - throw new DataGridInternalException( "An attempt was made to reset a group with a null child GeneratorNode.", m_dataGridControl ); + throw DataGridException.Create( "An attempt was made to reset a group with a null child GeneratorNode.", m_dataGridControl ); this.HandleSameLevelGroupReset( node.Child ); } @@ -3759,11 +3573,50 @@ namespace Xceed.Wpf.DataGrid } } + private void OnGeneratorNodeHeadersFootersCollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) + { + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_OnGeneratorNodeHeadersFootersCollectionChanged ) ) + { + if( this.IsHandlingGlobalItemsResetLocally ) + { + this.TraceEvent( TraceEventType.Warning, DataGridTraceEventId.CustomItemContainerGenerator_OnGeneratorNodeHeadersFootersCollectionChanged, DataGridTraceMessages.CannotProcessOnReset ); + return; + } + + if( this.Status == GeneratorStatus.GeneratingContainers ) + throw DataGridException.Create( "Cannot perform this operation while the generator is busy generating items.", m_dataGridControl ); + + var nodes = ( IEnumerable )sender; + Debug.Assert( nodes != null ); + Debug.Assert( nodes.Any() ); + + e = e.GetRangeActionOrSelf(); + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_OnGeneratorNodeHeadersFootersCollectionChanged, DataGridTraceArgs.Action( e.Action ) ); + + switch( e.Action ) + { + case NotifyCollectionChangedAction.Add: + this.HandleHeadersFootersAddition( nodes, e ); + break; + + case NotifyCollectionChangedAction.Remove: + case NotifyCollectionChangedAction.Move: + case NotifyCollectionChangedAction.Replace: + this.HandleHeadersFootersRemoveMoveReplace( nodes, e ); + break; + + case NotifyCollectionChangedAction.Reset: + this.HandleGlobalItemsReset(); + break; + } + } + } + private void OnViewThemeChanged( object sender, EventArgs e ) { if( this.Status == GeneratorStatus.GeneratingContainers ) - DataGridException.ThrowSystemException( "Cannot perform this operation while the generator is busy generating items.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "Cannot perform this operation while the generator is busy generating items.", m_dataGridControl ); if( m_startNode != null ) { @@ -3778,105 +3631,110 @@ namespace Xceed.Wpf.DataGrid this.CleanupGenerator(); } - private void ResetNodeList() + private void OnRecyclingPoolsContainersRemoved( object sender, ContainersRemovedEventArgs e ) { + this.OnContainersRemoved( e.RemovedContainers ); + } + private void ResetNodeList() + { this.UpdateHeaders( m_dataGridContext.Headers ); int addCount; this.SetupInitialItemsNodes( out addCount ); this.UpdateFooters( m_dataGridContext.Footers ); - - //Add self to the RecyclingManager ref count manager. - //This is to ensure that the list of container availlable for recycling will be preserved taking this generator into consideration - m_dataGridContext.RecyclingManager.AddRef( this ); } private int ClearItems() { - int retval = 0; - //if the first item is not null, that means that we have items within the grid. - if( m_firstItem != null ) - { - GeneratorNode previous = m_firstItem.Previous; + if( m_firstItem == null ) + return 0; - //there are footers items - if( m_firstFooter != null ) + var previous = m_firstItem.Previous; + + //there are footers items + if( m_firstFooter != null ) + { + //there is a previous item (headers present) + if( previous != null ) { - //there is a previous item (headers present) - if( previous != null ) - { - m_firstFooter.Previous.Next = null; //clear the next pointer from the last item - m_firstFooter.Previous = previous; //set the last header as the previous from the first footer - previous.Next = m_firstFooter; //set the first footer as the next from the last header - } - else - { - //there is no header present - m_firstFooter.Previous.Next = null; //set the last item next to null (protect again recursive clearing) - m_firstFooter.Previous = null; //make the first footer have not previous + m_firstFooter.Previous.Next = null; //clear the next pointer from the last item + m_firstFooter.Previous = previous; //set the last header as the previous from the first footer + previous.Next = m_firstFooter; //set the first footer as the next from the last header + } + else + { + //there is no header present + m_firstFooter.Previous.Next = null; //set the last item next to null (protect again recursive clearing) + m_firstFooter.Previous = null; //make the first footer have not previous - m_startNode = m_firstFooter; - } + m_startNode = m_firstFooter; + } + } + else + { + //There is no footers after the items. + if( previous != null ) + { + //this means we have some headers before the items. + previous.Next = null; } else { - //There is no footers after the items. - if( previous != null ) - { - //this means we have some headers before the items. - previous.Next = null; - } - else - { - //this means we have no headers before the items and no footers after. - m_startNode = null; - } + //this means we have no headers before the items and no footers after. + m_startNode = null; } + } - int removeCount; - int chainLength; - GeneratorNodeHelper.EvaluateChain( m_firstItem, out removeCount, out chainLength ); + int removeCount; + int chainLength; + GeneratorNodeHelper.EvaluateChain( m_firstItem, out removeCount, out chainLength ); - this.ClearLateGroupLevelDescriptions(); - m_groupNodeMappingCache.Clear(); - this.NodeFactory.CleanGeneratorNodeTree( m_firstItem ); - m_firstItem = null; + this.ClearLateGroupLevelDescriptions(); + m_groupNodeMappingCache.Clear(); - retval = removeCount; - } + this.NodeFactory.CleanGeneratorNodeTree( m_firstItem ); + m_firstItem = null; - return retval; + this.InvalidateNodeTree(); + + return removeCount; + } + + private void ClearRecyclingPools() + { + // Only the top most generator may clear the recycling pools. + if( m_dataGridContext.SourceDetailConfiguration != null ) + return; + + m_recyclingPools.Clear(); } private int RemoveGeneratedItem( int index, IList removedContainers ) { - //basic error handling if( ( index < 0 ) || ( index >= m_genPosToIndex.Count ) ) return 0; - object item = m_genPosToItem[ index ]; - DependencyObject container = m_genPosToContainer[ index ]; - GeneratorNode node = m_genPosToNode[ index ]; + Debug.Assert( ( m_genPosToContainer.Count == m_genPosToIndex.Count ) + && ( m_genPosToIndex.Count == m_genPosToItem.Count ) + && ( m_genPosToItem.Count == m_genPosToNode.Count ) ); - m_log.Assert( this, ( m_genPosToContainer.Count != 0 ) - && ( m_genPosToIndex.Count != 0 ) - && ( m_genPosToItem.Count != 0 ) - && ( m_genPosToNode.Count != 0 ), "Internal Generator's lists are empty, cannot continue to process RemoveGeneratedItems" ); + var item = m_genPosToItem[ index ]; + var container = m_genPosToContainer[ index ]; + var node = m_genPosToNode[ index ]; //remove the item from the 4 lists... (same as doing a "remove") this.GenPosArraysRemoveAt( index ); if( removedContainers != null ) { - removedContainers.Add( container ); + removedContainers.Insert( 0, container ); } - DetailGeneratorNode detailNode = node as DetailGeneratorNode; - //to ensure this is only done once, check if the node associated with the container is a Detail or not + var detailNode = node as DetailGeneratorNode; if( detailNode == null ) { //Node for item is NOT a detail, can safelly remove the container locally (int this generator instance). @@ -3893,34 +3751,30 @@ namespace Xceed.Wpf.DataGrid private int RemoveGeneratedItem( DependencyObject container ) { - int index = m_genPosToContainer.IndexOf( container ); - - if( index == -1 ) + var index = m_genPosToContainer.IndexOf( container ); + if( index < 0 ) return 0; return this.RemoveGeneratedItem( index, null ); } - private int RemoveGeneratedItems( int startIndex, int endIndex, IList removedContainers ) + private void RemoveGeneratedItems( int startIndex, int endIndex, IList removedContainers ) { if( startIndex > endIndex ) - return 0; + return; var count = m_genPosToIndex.Count; if( ( count <= 0 ) || ( m_genPosToIndex[ 0 ] > endIndex ) || ( m_genPosToIndex[ count - 1 ] < startIndex ) ) - return 0; + return; - var removed = 0; + Debug.Assert( ( m_genPosToContainer.Count == m_genPosToIndex.Count ) + && ( m_genPosToIndex.Count == m_genPosToItem.Count ) + && ( m_genPosToItem.Count == m_genPosToNode.Count ) ); //cycle through the list of generated items, and see if any items are generated between the indexes in the removed range. //start from the end so that removing an item will not cause the indexes to shift. for( var i = count - 1; i >= 0; i-- ) { - m_log.Assert( this, ( m_genPosToContainer.Count != 0 ) - && ( m_genPosToIndex.Count != 0 ) - && ( m_genPosToItem.Count != 0 ) - && ( m_genPosToNode.Count != 0 ), "Internal Generator's lists are empty, cannot continue to process RemoveGeneratedItems" ); - var index = m_genPosToIndex[ i ]; //if the item is within the range removed @@ -3929,30 +3783,25 @@ namespace Xceed.Wpf.DataGrid //this will ensure to recurse the call to the appropriate Detail Generator for clearing of the container. //otherwise, it will only remove it from the list of container generated in the current generator instance. this.RemoveGeneratedItem( i, removedContainers ); - - removed++; } } - - return removed; } - private int RemoveGeneratedItems( GeneratorNode referenceNode, IList removedContainers ) + private void RemoveGeneratedItems( GeneratorNode referenceNode, IList removedContainers ) { - int genCountRemoved = 0; + var toRemove = new List(); - List toRemove = new List(); toRemove.Add( referenceNode ); - ItemsGeneratorNode itemsNode = referenceNode as ItemsGeneratorNode; + var itemsNode = referenceNode as ItemsGeneratorNode; if( itemsNode != null ) { if( itemsNode.Details != null ) { //cycle through all the details currently mapped to the reference node - foreach( KeyValuePair> detailsForNode in itemsNode.Details ) + foreach( var detailsForNode in itemsNode.Details ) { - foreach( DetailGeneratorNode detailNode in detailsForNode.Value ) + foreach( var detailNode in detailsForNode.Value ) { toRemove.Add( detailNode ); } @@ -3964,7 +3813,7 @@ namespace Xceed.Wpf.DataGrid //start from the end so that removing an item will not cause the indexes to shift for( int i = m_genPosToNode.Count - 1; i >= 0; i-- ) { - GeneratorNode node = m_genPosToNode[ i ]; + var node = m_genPosToNode[ i ]; //if the item is within the range removed if( toRemove.Contains( node ) ) @@ -3972,94 +3821,131 @@ namespace Xceed.Wpf.DataGrid //this will ensure to recurse the call to the appropriate Detail Generator for clearing of the container. //otherwise, it will only remove it from the list of container generated in the current generator instance. this.RemoveGeneratedItem( i, removedContainers ); - - //increment realized item count removed - genCountRemoved++; } } - - return genCountRemoved; } private void RemoveAllGeneratedItems() { - m_log.Assert( this.IsHandlingGlobalItemsReset, "IsHandlingGlobalItemsReset is not set." ); + Debug.Assert( this.IsHandlingGlobalItemsReset, "A flag is not set." ); - using( m_log.BeginBlock( this, null ) ) + //Call RemoveAllGeneratedItems() on all the detail generators + foreach( var generator in this.GetDetailGenerators() ) { - //Call RemoveAllGeneratedItems() on all the detail generators - foreach( var generator in this.GetDetailGenerators() ) - { - generator.RemoveAllGeneratedItems(); - } - - //then we can clean the list of items of items generated held by this generator - int genCountRemoved = m_genPosToNode.Count; - - //start from the end so that removing an item will not cause the indexes to shift - for( int i = genCountRemoved - 1; i >= 0; i-- ) - { - GeneratorNode node = m_genPosToNode[ i ]; - DependencyObject container = m_genPosToContainer[ i ]; + generator.RemoveAllGeneratedItems(); + } - //if item is NOT a detail - if( !( node is DetailGeneratorNode ) ) - { - // Clear it. - this.RemoveContainer( container, m_genPosToItem[ i ] ); - } + //then we can clean the list of items of items generated held by this generator + var genCountRemoved = m_genPosToNode.Count; - //Note: there is no need to call "RemoveContainer" on the "detail" items... since RemoveAllGeneratedItems() was called - // on all detail generators already. + //start from the end so that removing an item will not cause the indexes to shift + for( int i = genCountRemoved - 1; i >= 0; i-- ) + { + var node = m_genPosToNode[ i ]; + var container = m_genPosToContainer[ i ]; - this.GenPosArraysRemoveAt( i ); + //if item is NOT a detail + if( !( node is DetailGeneratorNode ) ) + { + // Clear it. + this.RemoveContainer( container, m_genPosToItem[ i ] ); } + + //Note: there is no need to call "RemoveContainer" on the "detail" items... since RemoveAllGeneratedItems() was called + // on all detail generators already. + this.GenPosArraysRemoveAt( i ); } } private bool RemoveGeneratedItems( HeadersFootersGeneratorNode referenceNode, object referenceItem, IList removedContainers ) { - bool retval = false; - //cycle through the list of generated items, and see if any items are generated between the indexes in the removed range. //start from the end so that removing an item will not cause the indexes to shift for( int i = m_genPosToNode.Count - 1; i >= 0; i-- ) { - GeneratorNode node = m_genPosToNode[ i ]; + var node = m_genPosToNode[ i ]; //if the item is within the range removed if( node == referenceNode ) { - object item = m_genPosToItem[ i ]; + var item = m_genPosToItem[ i ]; if( item.Equals( referenceItem ) ) { - DependencyObject container = m_genPosToContainer[ i ]; - removedContainers.Add( container ); - - this.RemoveContainer( container, referenceItem ); + var container = m_genPosToContainer[ i ]; - retval = true; + if( removedContainers != null ) + { + removedContainers.Add( container ); + } + this.RemoveContainer( container, referenceItem ); this.GenPosArraysRemoveAt( i ); - break; + return true; } } } - return retval; + return false; + } + + private void RemoveContainer( DependencyObject container, object dataItem ) + { + m_dataGridControl.ClearItemContainer( container, dataItem ); + + var isContainerRecycled = false; + + if( this.IsRecyclingEnabled ) + { + isContainerRecycled = this.EnqueueContainer( container, dataItem ); + + var dataItemStore = container.ReadLocalValue( CustomItemContainerGenerator.DataItemPropertyProperty ) as DataItemDataProviderBase; + if( dataItemStore != null ) + { + dataItemStore.ClearDataItem(); + } + } + + //If recycling is not enabled, or if the container could not be enqueued, make sure it is removed from the DataGridItemsHost's child collection. + if( !isContainerRecycled ) + { + Debug.Assert( container != null ); + this.OnContainersRemoved( new DependencyObject[] { container } ); + } + } + + private void RemoveDetailContainers( IEnumerable containers ) + { + if( containers == null ) + return; + + var toRemove = new HashSet( containers ); + if( toRemove.Count <= 0 ) + return; + + for( int i = m_genPosToContainer.Count - 1; i >= 0; i-- ) + { + if( !toRemove.Contains( m_genPosToContainer[ i ] ) ) + continue; + + this.GenPosArraysRemoveAt( i ); + } } private void GenPosArraysRemoveAt( int index ) { //remove the item from the 4 lists... (same as doing a "remove") - ItemsGeneratorNode itemsNode = m_genPosToNode[ index ] as ItemsGeneratorNode; + var itemsNode = m_genPosToNode[ index ] as ItemsGeneratorNode; // Unlock DataVirtualization hold on item's page. if( itemsNode != null ) + { this.UpdateDataVirtualizationLockForItemsNode( itemsNode, m_genPosToItem[ index ], false ); + } + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_GenPosArraysRemoveAt, DataGridTraceMessages.ContainerRemoved, DataGridTraceArgs.Container( m_genPosToContainer[ index ] ), DataGridTraceArgs.Node( m_genPosToNode[ index ] ), DataGridTraceArgs.Item( m_genPosToItem[ index ] ), DataGridTraceArgs.GeneratorIndex( index ), DataGridTraceArgs.Index( m_genPosToIndex[ index ] ) ); m_genPosToContainer.RemoveAt( index ); m_genPosToIndex.RemoveAt( index ); @@ -4069,73 +3955,71 @@ namespace Xceed.Wpf.DataGrid private void UpdateHeaders( IList headers ) { + //If the m_firstHeader is not NULL, then there is nothing to do, since the Header node contains an observable collection + //which we monitor otherwise. + if( m_firstHeader != null ) + return; - //if there was no header prior this udpate. - if( m_firstHeader == null ) + //create the node(s) that would contain the headers + m_firstHeader = this.CreateHeaders( headers ); + + int count; + int chainLength; + GeneratorNodeHelper.EvaluateChain( m_firstHeader, out count, out chainLength ); + + //if there was items present in the linked list. + if( m_startNode != null ) + { + //headers are automatically inserted at the beginning + var nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + nodeHelper.InsertBefore( m_firstHeader ); + } + else { - //create the node(s) that would contain the headers - m_firstHeader = this.CreateHeaders( headers ); + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_UpdateHeaders, DataGridTraceMessages.NewTreeCreated, DataGridTraceArgs.Node( m_firstHeader ) ); + } + //set the start node as the first header node. + m_startNode = m_firstHeader; + + this.InvalidateNodeTree(); + } + + private void UpdateFooters( IList footers ) + { + //If the m_firstHeader is not NULL, then there is nothing to do, since the Header node contains an observable collection + //which we monitor otherwise. + if( m_firstFooter != null ) + return; + + //create the node(s) that would contain the footers + m_firstFooter = this.CreateFooters( footers ); + + //if there are no footers, then the m_firstFooter will remain null + if( m_firstFooter != null ) + { int count; int chainLength; - GeneratorNodeHelper.EvaluateChain( m_firstHeader, out count, out chainLength ); + GeneratorNodeHelper.EvaluateChain( m_firstFooter, out count, out chainLength ); //if there was items present in the linked list. if( m_startNode != null ) { - //headers are automatically inserted at the beginning + //since we called ClearFooters earlier, I can just go at the end of the list of items GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); - nodeHelper.InsertBefore( m_firstHeader ); + + nodeHelper.MoveToEnd(); + nodeHelper.InsertAfter( m_firstFooter ); } else { - m_log.WriteLine( this, "UpdateHeaders - new tree" ); - } + m_startNode = m_firstFooter; - //set the start node as the first header node. - m_startNode = m_firstHeader; + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_UpdateFooters, DataGridTraceMessages.NewStartNode, DataGridTraceArgs.Node( m_startNode ) ); + } } - //If the m_firstHeader is not NULL, then there is nothing to do, since the Header node contains an observable collection - //which we monitor otherwise. - } - - private void UpdateFooters( IList footers ) - { - - //if there was no header prior this udpate. - if( m_firstFooter == null ) - { - //create the node(s) that would contain the footers - m_firstFooter = this.CreateFooters( footers ); - - //if there are no footers, then the m_firstFooter will remain null - if( m_firstFooter != null ) - { - int count; - int chainLength; - GeneratorNodeHelper.EvaluateChain( m_firstFooter, out count, out chainLength ); - - //if there was items present in the linked list. - if( m_startNode != null ) - { - //since we called ClearFooters earlier, I can just go at the end of the list of items - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); - - nodeHelper.MoveToEnd(); - nodeHelper.InsertAfter( m_firstFooter ); - } - else - { - m_startNode = m_firstFooter; - - m_log.WriteLine( this, "UpdateFooters - new tree" ); - } - } - } - - //If the m_firstHeader is not NULL, then there is nothing to do, since the Header node contains an observable collection - //which we monitor otherwise. + this.InvalidateNodeTree(); } private HeadersFootersGeneratorNode CreateHeaders( IList headers ) @@ -4150,10 +4034,10 @@ namespace Xceed.Wpf.DataGrid private GeneratorNode SetupInitialItemsNodes( out int addCount ) { - GeneratorNode newItemNode = null; - addCount = 0; + var newItemNode = default( GeneratorNode ); + this.RefreshGroupsCollection(); //this function should only be called when the m_firstItem is null. @@ -4180,8 +4064,8 @@ namespace Xceed.Wpf.DataGrid //if there is a footer node, then the insertion point is just before the footer node (if there is anything before!) if( m_firstFooter != null ) { - GeneratorNode originalPrevious = m_firstFooter.Previous; - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_firstFooter, 0, 0 ); //do not care about index! + var originalPrevious = m_firstFooter.Previous; + var nodeHelper = new GeneratorNodeHelper( m_firstFooter, 0, 0 ); //do not care about index! nodeHelper.InsertBefore( m_firstItem ); @@ -4192,7 +4076,7 @@ namespace Xceed.Wpf.DataGrid } else if( m_firstHeader != null ) //if there is no footer but some headers, add it at the end. { - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_firstHeader, 0, 0 ); //do not care about index! + var nodeHelper = new GeneratorNodeHelper( m_firstHeader, 0, 0 ); //do not care about index! nodeHelper.MoveToEnd(); nodeHelper.InsertAfter( m_firstItem ); @@ -4200,15 +4084,17 @@ namespace Xceed.Wpf.DataGrid else { //this case should not be possible: no header, no footers but there is a startNode - throw new DataGridInternalException( "No start node found for the current GeneratorNode.", m_dataGridControl ); + throw DataGridException.Create( "No start node found for the current GeneratorNode.", m_dataGridControl ); } } else { m_startNode = m_firstItem; - m_log.WriteLine( this, "SetupInitialItemsNodes - new tree" ); + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_SetupInitialItemsNodes, DataGridTraceMessages.NewStartNode, DataGridTraceArgs.Node( m_startNode ) ); } + + this.InvalidateNodeTree(); } return newItemNode; @@ -4237,7 +4123,7 @@ namespace Xceed.Wpf.DataGrid { var list = CustomItemContainerGenerator.GetList( m_collectionView ); - return this.NodeFactory.CreateItemsGeneratorNode( list, null, null, null, this ); + return this.NodeFactory.CreateItemsGeneratorNode( list, null, null, null ); } private GeneratorNode CreateGroupListFromCollection( IList collection, GeneratorNode parentNode ) @@ -4245,24 +4131,23 @@ namespace Xceed.Wpf.DataGrid if( collection.Count == 0 ) return null; - GeneratorNode rootNode = null; - GeneratorNode previousNode = null; - GroupGeneratorNode actualNode = null; + var rootNode = default( GeneratorNode ); + var previousNode = default( GeneratorNode ); + var actualNode = default( GroupGeneratorNode ); + var childNode = default( GeneratorNode ); + var level = ( parentNode == null ) ? 0 : parentNode.Level + 1; - GeneratorNode childNode = null; - int level = ( parentNode == null ) ? 0 : parentNode.Level + 1; GroupConfiguration groupConfig; bool initiallyExpanded; - ObservableCollection groupDescriptions = DataGridContext.GetGroupDescriptionsHelper( m_collectionView ); - GroupConfigurationSelector groupConfigurationSelector = m_dataGridContext.GroupConfigurationSelector; - LateGroupLevelDescription lateGroupLevelDescription = this.CreateOrGetLateGroupLevelDescription( level, groupDescriptions ); + var groupDescriptions = DataGridContext.GetGroupDescriptionsHelper( m_collectionView ); + var groupConfigurationSelector = m_dataGridContext.GroupConfigurationSelector; + var lateGroupLevelDescription = this.CreateOrGetLateGroupLevelDescription( level, groupDescriptions ); foreach( CollectionViewGroup group in collection ) { groupConfig = GroupConfiguration.GetGroupConfiguration( m_dataGridContext, groupDescriptions, groupConfigurationSelector, level, group ); - - m_log.Assert( this, groupConfig != null, "groupConfig != null" ); + Debug.Assert( groupConfig != null ); if( groupConfig.UseDefaultHeadersFooters ) { @@ -4287,17 +4172,17 @@ namespace Xceed.Wpf.DataGrid childNode = this.SetupGroupHeaders( groupConfig, actualNode ); actualNode.Child = childNode; - GeneratorNodeHelper childNodeHelper = new GeneratorNodeHelper( childNode, 0, 0 ); //do not care about index. + var childNodeHelper = new GeneratorNodeHelper( childNode, 0, 0 ); //do not care about index. childNodeHelper.MoveToEnd(); //extensibility, just in case SetupGroupHeaders() ever return a node list. - IList subItems = group.GetItems(); + var subItems = group.GetItems(); //if the node newly created is not the bottom level if( !group.IsBottomLevel ) { if( ( subItems != null ) && ( subItems.Count > 0 ) ) { - GeneratorNode subGroupsNode = this.CreateGroupListFromCollection( subItems as IList, actualNode ); + var subGroupsNode = this.CreateGroupListFromCollection( subItems as IList, actualNode ); if( subGroupsNode != null ) { childNodeHelper.InsertAfter( subGroupsNode ); @@ -4307,7 +4192,7 @@ namespace Xceed.Wpf.DataGrid else { //this is the bottom level, create an Items node - GeneratorNode itemsNode = this.NodeFactory.CreateItemsGeneratorNode( subItems as IList, actualNode, null, null, this ); + var itemsNode = this.NodeFactory.CreateItemsGeneratorNode( subItems as IList, actualNode, null, null ); if( itemsNode != null ) { childNodeHelper.InsertAfter( itemsNode ); @@ -4376,91 +4261,88 @@ namespace Xceed.Wpf.DataGrid return this.NodeFactory.CreateHeadersFootersGeneratorNode( groupConfig.Headers, actualNode, null, null ); } - private GeneratorPosition HandleParentGroupRemove( GeneratorNode parent, out int countRemoved, out int genCountRemoved, out int removeIndex, NotifyCollectionChangedEventArgs e, IList removedContainers ) + private void HandleParentGroupRemove( GeneratorNode parent, out int countRemoved, NotifyCollectionChangedEventArgs e, IList removedContainers ) { - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( parent, 0, 0 ); //do not care about index (for now). + var nodeHelper = new GeneratorNodeHelper( parent, 0, 0 ); //do not care about index (for now). // start by moving to the first child... of the node (GroupHeaders node, most probably). // false parameter is to prevent skipping over a collapsed node (item count 0 ) if( !nodeHelper.MoveToChild( false ) ) //could not advance to the child item so there is no items to be removed... - throw new DataGridInternalException( "No child item in the group to remove.", m_dataGridControl ); + throw DataGridException.Create( "No child item in the group to remove.", m_dataGridControl ); - return this.HandleSameLevelGroupRemove( nodeHelper.CurrentNode, out countRemoved, out genCountRemoved, out removeIndex, e, removedContainers ); + this.HandleSameLevelGroupRemove( nodeHelper.CurrentNode, out countRemoved, e, removedContainers ); } - private GeneratorPosition HandleSameLevelGroupRemove( GeneratorNode firstChild, out int countRemoved, out int genCountRemoved, out int removeIndex, NotifyCollectionChangedEventArgs e, IList removedContainers ) + private void HandleSameLevelGroupRemove( GeneratorNode firstChild, out int countRemoved, NotifyCollectionChangedEventArgs e, IList removedContainers ) { - GeneratorPosition retval; - - countRemoved = 0; - genCountRemoved = 0; + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_HandleSameLevelGroupRemove ) ) + { + countRemoved = 0; - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( firstChild, 0, 0 ); - nodeHelper.ReverseCalculateIndex(); + var nodeHelper = new GeneratorNodeHelper( firstChild, 0, 0 ); + nodeHelper.ReverseCalculateIndex(); - //Advance to the first "Group" node (skip the GroupHeaders) - while( !( nodeHelper.CurrentNode is GroupGeneratorNode ) ) - { - if( !nodeHelper.MoveToNext() ) - throw new DataGridInternalException( "Unable to move to next GeneratorNode.", m_dataGridControl ); - } + //Advance to the first "Group" node (skip the GroupHeaders) + while( !( nodeHelper.CurrentNode is GroupGeneratorNode ) ) + { + if( !nodeHelper.MoveToNext() ) + throw DataGridException.Create( "Unable to move to next GeneratorNode.", m_dataGridControl ); + } - //then move up to the removal start point. - if( !nodeHelper.MoveToNextBy( e.OldStartingIndex ) ) - throw new DataGridInternalException( "Unable to move to the requested generator index.", m_dataGridControl ); + //then move up to the removal start point. + if( !nodeHelper.MoveToNextBy( e.OldStartingIndex ) ) + throw DataGridException.Create( "Unable to move to the requested generator index.", m_dataGridControl ); - GroupGeneratorNode startNode = nodeHelper.CurrentNode as GroupGeneratorNode; - removeIndex = -1; + var startNode = nodeHelper.CurrentNode as GroupGeneratorNode; + var removeIndex = -1; - //Only fetch the index if the group itself is not "collapsed" or under a collapsed group already - if( ( startNode.IsExpanded == startNode.IsComputedExpanded ) && ( startNode.ItemCount > 0 ) ) - { - removeIndex = nodeHelper.Index; - retval = this.GeneratorPositionFromIndex( removeIndex ); - } - else - { - retval = new GeneratorPosition( -1, 1 ); - } + //Only fetch the index if the group itself is not "collapsed" or under a collapsed group already + if( ( startNode.IsExpanded == startNode.IsComputedExpanded ) && ( startNode.ItemCount > 0 ) ) + { + removeIndex = nodeHelper.Index; + } - //retrieve the generator position for the first item to remove. + //retrieve the generator position for the first item to remove. + this.ProcessGroupRemoval( startNode, e.OldItems.Count, true, out countRemoved ); - this.ProcessGroupRemoval( startNode, e.OldItems.Count, true, out countRemoved ); + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_HandleSameLevelGroupRemove, DataGridTraceMessages.GroupNodeRemoved, DataGridTraceArgs.Node( startNode ), DataGridTraceArgs.ItemCount( countRemoved ) ); - //Clean the chain "isolated" previously - this.NodeFactory.CleanGeneratorNodeTree( startNode ); + //Clean the chain "isolated" previously + this.NodeFactory.CleanGeneratorNodeTree( startNode ); - if( removeIndex != -1 ) - { - //remove the appropriate - genCountRemoved = this.RemoveGeneratedItems( removeIndex, removeIndex + countRemoved - 1, removedContainers ); + if( removeIndex >= 0 ) + { + this.RemoveGeneratedItems( removeIndex, removeIndex + countRemoved - 1, removedContainers ); + } } - - return retval; } private GroupGeneratorNode ProcessGroupRemoval( GeneratorNode startNode, int removeCount, bool updateGroupNodeMappingCache, out int countRemoved ) { - m_log.Assert( this, removeCount != 0, "remove count cannot be 0" ); - - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( startNode, 0, 0 );//index not important. - GroupGeneratorNode parentGroup = startNode.Parent as GroupGeneratorNode; - int i = 0; - countRemoved = 0; + var nodeHelper = new GeneratorNodeHelper( startNode, 0, 0 ); //index not important. + var parentGroup = startNode.Parent as GroupGeneratorNode; + var i = 0; + do { - GroupGeneratorNode group = nodeHelper.CurrentNode as GroupGeneratorNode; + var group = nodeHelper.CurrentNode as GroupGeneratorNode; + if( group == null ) + { + this.TraceEvent( TraceEventType.Warning, DataGridTraceEventId.CustomItemContainerGenerator_ProcessGroupRemoval, DataGridTraceMessages.UnexpectedNode, DataGridTraceArgs.Node( nodeHelper.CurrentNode ) ); + } + else + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ProcessGroupRemoval, DataGridTraceMessages.GroupNodeRemoved, DataGridTraceArgs.Node( group ), DataGridTraceArgs.ItemCount( group.ItemCount ) ); + } if( updateGroupNodeMappingCache ) { m_groupNodeMappingCache.Remove( group.CollectionViewGroup ); } - m_log.Assert( this, group != null, "node to be removed must be a GroupGeneratorNode" ); - //add the total number of child to the count of items removed. countRemoved += group.ItemCount; @@ -4469,14 +4351,14 @@ namespace Xceed.Wpf.DataGrid if( i < removeCount ) { if( !nodeHelper.MoveToNext() ) - throw new DataGridInternalException( "Could not move to the last node to be removed.", m_dataGridControl ); + throw DataGridException.Create( "Could not move to the last node to be removed.", m_dataGridControl ); } } while( i < removeCount ); //disconnect the node chain to be removed from the linked list. - GeneratorNode previous = startNode.Previous; - GeneratorNode next = nodeHelper.CurrentNode.Next; + var previous = startNode.Previous; + var next = nodeHelper.CurrentNode.Next; if( next != null ) { @@ -4515,9 +4397,14 @@ namespace Xceed.Wpf.DataGrid { m_startNode = next; } + + this.InvalidateNodeTree(); } - m_log.Assert( this, nodeHelper.CurrentNode is GroupGeneratorNode, "last node is not a GroupGeneratorNode" ); + if( !( nodeHelper.CurrentNode is GroupGeneratorNode ) ) + { + this.TraceEvent( TraceEventType.Warning, DataGridTraceEventId.CustomItemContainerGenerator_ProcessGroupRemoval, DataGridTraceMessages.UnexpectedNode, DataGridTraceArgs.LastNode( nodeHelper.CurrentNode ) ); + } return ( GroupGeneratorNode )nodeHelper.CurrentNode; } @@ -4526,111 +4413,41 @@ namespace Xceed.Wpf.DataGrid { Debug.Assert( node != null ); - var parentNode = node.Parent as GroupGeneratorNode; - var oldGroups = new List(); - var nodeHelper = new GeneratorNodeHelper( node, 0, 0 ); - - do + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_HandleSameLevelGroupReset ) ) { - var groupNode = nodeHelper.CurrentNode as GroupGeneratorNode; - if( groupNode != null ) + var parentNode = node.Parent as GroupGeneratorNode; + var oldGroups = new List(); + var nodeHelper = new GeneratorNodeHelper( node, 0, 0 ); + + do { - Debug.Assert( groupNode.CollectionViewGroup != null ); - oldGroups.Add( groupNode.CollectionViewGroup ); + var groupNode = nodeHelper.CurrentNode as GroupGeneratorNode; + if( groupNode != null ) + { + Debug.Assert( groupNode.CollectionViewGroup != null ); + oldGroups.Add( groupNode.CollectionViewGroup ); + } } - } - while( nodeHelper.MoveToNext() ); - - var newGroups = ( parentNode != null ) - ? parentNode.CollectionViewGroup.GetItems().Cast().ToList() - : m_groupsCollection.Cast().ToList(); - - // If nothing has changed, avoid the heavy process of finding out which groups have been added, - // removed and moved. - if( newGroups.Count == oldGroups.Count ) - { - if( newGroups.SequenceEqual( oldGroups ) ) - return; - } - - var groupsAdded = default( ICollection ); - var groupsRemoved = default( ICollection ); - var groupsMoved = default( ICollection ); - - this.GetGroupChanges( oldGroups, newGroups, out groupsAdded, out groupsRemoved, out groupsMoved ); - - if( groupsAdded.Count + groupsRemoved.Count + groupsMoved.Count > CustomItemContainerGenerator.GlobalItemsResetThreshold ) - { - this.HandleGlobalItemsReset(); - } - else - { - this.ApplyGroupChanges( node, oldGroups, newGroups, groupsAdded, groupsRemoved, groupsMoved ); - } - } - - private void GetGroupChanges( - IList oldGroups, - IList newGroups, - out ICollection groupsAdded, - out ICollection groupsRemoved, - out ICollection groupsMoved ) - { - Debug.Assert( oldGroups != null ); - Debug.Assert( newGroups != null ); - - groupsAdded = new HashSet(); - groupsRemoved = new HashSet(); - groupsMoved = new HashSet(); - - var oldGroupsPositions = new Dictionary(); - - for( var i = 0; i < oldGroups.Count; i++ ) - { - oldGroupsPositions.Add( oldGroups[ i ], i ); - } + while( nodeHelper.MoveToNext() ); - var sequence = new List( newGroups.Count ); - var isAlive = new BitArray( oldGroups.Count, false ); - - foreach( var group in newGroups ) - { - int index; + var newGroups = ( parentNode != null ) + ? parentNode.CollectionViewGroup.GetItems().Cast().ToList() + : m_groupsCollection.Cast().ToList(); - if( oldGroupsPositions.TryGetValue( group, out index ) ) - { - isAlive[ index ] = true; - sequence.Add( index ); - } - else + // If nothing has changed, avoid the heavy process of finding out which groups have been added, + // removed and moved. + if( newGroups.Count == oldGroups.Count ) { - Debug.Assert( !m_groupNodeMappingCache.ContainsKey( group ), "How come there is a node for the group." ); - - groupsAdded.Add( group ); + if( newGroups.SequenceEqual( oldGroups ) ) + return; } - } - - var hasNotMoved = new BitArray( oldGroups.Count, false ); - // The subsequence contains the position of the old groups that are in the new groups and that have not moved. - foreach( var index in LongestIncreasingSubsequence.Find( sequence ) ) - { - hasNotMoved[ index ] = true; - } + var groupsAdded = new HashSet(); + var groupsRemoved = new HashSet(); + var groupsMoved = new HashSet(); - for( var i = 0; i < oldGroups.Count; i++ ) - { - if( isAlive[ i ] ) - { - if( !hasNotMoved[ i ] ) - { - groupsMoved.Add( oldGroups[ i ] ); - } - } - else - { - groupsRemoved.Add( oldGroups[ i ] ); - } + CustomItemContainerGenerator.FindChanges( oldGroups, newGroups, groupsAdded, groupsRemoved, groupsMoved ); + this.ApplyGroupChanges( node, oldGroups, newGroups, groupsAdded, groupsRemoved, groupsMoved ); } } @@ -4725,10 +4542,12 @@ namespace Xceed.Wpf.DataGrid if( insertAfter ) { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ApplyGroupChanges, DataGridTraceMessages.GroupNodeAdded, DataGridTraceArgs.Node( groupNode ), DataGridTraceArgs.PreviousNode( addNodeHelper.CurrentNode ) ); addNodeHelper.InsertAfter( groupNode ); } else { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ApplyGroupChanges, DataGridTraceMessages.GroupNodeAdded, DataGridTraceArgs.Node( groupNode ), DataGridTraceArgs.NextNode( addNodeHelper.CurrentNode ) ); addNodeHelper.InsertBefore( groupNode ); insertAfter = true; } @@ -4741,6 +4560,8 @@ namespace Xceed.Wpf.DataGrid } m_firstItem = groupNode; + + this.InvalidateNodeTree(); } } else @@ -4754,23 +4575,29 @@ namespace Xceed.Wpf.DataGrid if( m_firstFooter != null ) { var addNodeHelper = new GeneratorNodeHelper( m_firstFooter, 0, 0 ); + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ApplyGroupChanges, DataGridTraceMessages.GroupNodeAdded, DataGridTraceArgs.Node( groupNode ), DataGridTraceArgs.NextNode( addNodeHelper.CurrentNode ) ); addNodeHelper.InsertBefore( groupNode ); } else if( m_firstHeader != null ) { var addNodeHelper = new GeneratorNodeHelper( m_firstHeader, 0, 0 ); addNodeHelper.MoveToEnd(); + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ApplyGroupChanges, DataGridTraceMessages.GroupNodeAdded, DataGridTraceArgs.Node( groupNode ), DataGridTraceArgs.PreviousNode( addNodeHelper.CurrentNode ) ); addNodeHelper.InsertAfter( groupNode ); } else { - throw new DataGridInternalException( "No start node found for the current GeneratorNode.", m_dataGridControl ); + throw DataGridException.Create( "No start node found for the current GeneratorNode.", m_dataGridControl ); } } else { m_startNode = groupNode; } + + this.InvalidateNodeTree(); } else { @@ -4778,6 +4605,8 @@ namespace Xceed.Wpf.DataGrid var addNodeHelper = new GeneratorNodeHelper( parentNode.Child, 0, 0 ); addNodeHelper.MoveToEnd(); + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ApplyGroupChanges, DataGridTraceMessages.GroupNodeAdded, DataGridTraceArgs.Node( groupNode ), DataGridTraceArgs.PreviousNode( addNodeHelper.CurrentNode ) ); addNodeHelper.InsertAfter( groupNode ); } } @@ -4809,6 +4638,8 @@ namespace Xceed.Wpf.DataGrid Debug.Assert( groupNode != null ); var addNodeHelper = new GeneratorNodeHelper( m_groupNodeMappingCache[ newGroups[ i - 1 ] ], 0, 0 ); + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_ApplyGroupChanges, DataGridTraceMessages.GroupNodeAdded, DataGridTraceArgs.Node( groupNode ), DataGridTraceArgs.PreviousNode( addNodeHelper.CurrentNode ) ); addNodeHelper.InsertAfter( groupNode ); } } @@ -4819,318 +4650,434 @@ namespace Xceed.Wpf.DataGrid private void HandleSameLevelGroupMove( GeneratorNode node, NotifyCollectionChangedEventArgs e ) { - GroupGeneratorNode parentGroup = node.Parent as GroupGeneratorNode; - - //Start a NodeHelper on the first child of the node where the move occured. - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( node, 0, 0 ); - nodeHelper.ReverseCalculateIndex(); //determine index of the node. - - //Advance to the first "Group" node (skip the GroupHEaders) - while( !( nodeHelper.CurrentNode is GroupGeneratorNode ) ) + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_HandleSameLevelGroupMove ) ) { - if( !nodeHelper.MoveToNext() ) - throw new DataGridInternalException( "Unable to move to next GeneratorNode.", m_dataGridControl ); - } + var parentGroup = node.Parent as GroupGeneratorNode; - //then move up to the removal start point. - if( !nodeHelper.MoveToNextBy( e.OldStartingIndex ) ) - throw new DataGridInternalException( "Unable to move to the requested generator index.", m_dataGridControl ); + //Start a NodeHelper on the first child of the node where the move occured. + var nodeHelper = new GeneratorNodeHelper( node, 0, 0 ); + nodeHelper.ReverseCalculateIndex(); //determine index of the node. + + //Advance to the first "Group" node (skip the GroupHEaders) + while( !( nodeHelper.CurrentNode is GroupGeneratorNode ) ) + { + if( !nodeHelper.MoveToNext() ) + throw DataGridException.Create( "Unable to move to next GeneratorNode.", m_dataGridControl ); + } - //remember the current node as the start point of the move (will be used when "extracting the chain") - GeneratorNode startNode = nodeHelper.CurrentNode; - //also remember the index of the node, to calculate range of elements to remove (containers ) - int startIndex = nodeHelper.Index; + //then move up to the removal start point. + if( !nodeHelper.MoveToNextBy( e.OldStartingIndex ) ) + throw DataGridException.Create( "Unable to move to the requested generator index.", m_dataGridControl ); - //then, cumulate the total number of items in the groups concerned - int totalCountRemoved = 0; + //remember the current node as the start point of the move (will be used when "extracting the chain") + var startNode = nodeHelper.CurrentNode; + //also remember the index of the node, to calculate range of elements to remove (containers ) + var startIndex = nodeHelper.Index; - node = this.ProcessGroupRemoval( startNode, e.OldItems.Count, false, out totalCountRemoved ); + //then, cumulate the total number of items in the groups concerned + var totalCountRemoved = 0; - //send a message to the panel to remove the visual elements concerned - GeneratorPosition removeGenPos = this.GeneratorPositionFromIndex( startIndex ); + node = this.ProcessGroupRemoval( startNode, e.OldItems.Count, false, out totalCountRemoved ); - List removedContainers = new List(); - int genCountRemoved = this.RemoveGeneratedItems( startIndex, startIndex + totalCountRemoved - 1, removedContainers ); + //send a message to the panel to remove the visual elements concerned + var containers = new List(); - this.SendRemoveEvent( removeGenPos, startIndex, totalCountRemoved, genCountRemoved, removedContainers ); + this.RemoveGeneratedItems( startIndex, startIndex + totalCountRemoved - 1, containers ); + this.SendRemoveEvent( totalCountRemoved, containers ); - //reset the node parameter for the "re-addition" - node = ( parentGroup != null ) ? parentGroup.Child : m_firstItem; + //reset the node parameter for the "re-addition" + node = ( parentGroup != null ) ? parentGroup.Child : m_firstItem; - if( node == null ) - throw new DataGridInternalException( "No node found to move.", m_dataGridControl ); + if( node == null ) + throw DataGridException.Create( "No node found to move.", m_dataGridControl ); - //Once the chain was pulled out, re-insert it at the appropriate location. - nodeHelper = new GeneratorNodeHelper( node, 0, 0 ); //do not care about the index for what I need + //Once the chain was pulled out, re-insert it at the appropriate location. + nodeHelper = new GeneratorNodeHelper( node, 0, 0 ); //do not care about the index for what I need - //Advance to the first "Group" node (skip the GroupHEaders) - while( !( nodeHelper.CurrentNode is GroupGeneratorNode ) ) - { - if( !nodeHelper.MoveToNext() ) - throw new DataGridInternalException( "Unable to move to next GeneratorNode.", m_dataGridControl ); - } + //Advance to the first "Group" node (skip the GroupHEaders) + while( !( nodeHelper.CurrentNode is GroupGeneratorNode ) ) + { + if( !nodeHelper.MoveToNext() ) + throw DataGridException.Create( "Unable to move to next GeneratorNode.", m_dataGridControl ); + } - bool insertBefore = nodeHelper.MoveToNextBy( e.NewStartingIndex ); + bool insertBefore = nodeHelper.MoveToNextBy( e.NewStartingIndex ); - if( insertBefore ) - { - if( nodeHelper.CurrentNode == m_firstItem ) + if( insertBefore ) { - if( m_startNode == m_firstItem ) + if( nodeHelper.CurrentNode == m_firstItem ) { - m_startNode = startNode; + if( m_startNode == m_firstItem ) + { + m_startNode = startNode; + } + + m_firstItem = startNode; + + this.InvalidateNodeTree(); } - m_firstItem = startNode; + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_HandleSameLevelGroupMove, DataGridTraceMessages.GroupNodeAdded, DataGridTraceArgs.Node( startNode ), DataGridTraceArgs.NextNode( nodeHelper.CurrentNode ), DataGridTraceArgs.ItemCount( totalCountRemoved ) ); + nodeHelper.InsertBefore( startNode ); + } + else + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_HandleSameLevelGroupMove, DataGridTraceMessages.GroupNodeAdded, DataGridTraceArgs.Node( startNode ), DataGridTraceArgs.PreviousNode( nodeHelper.CurrentNode ), DataGridTraceArgs.ItemCount( totalCountRemoved ) ); + nodeHelper.InsertAfter( startNode ); } - //reinsert the chain at the specified location. - nodeHelper.InsertBefore( startNode ); - } - else - { - nodeHelper.InsertAfter( startNode ); + //and finally, call to increment the generation count for the generator content + this.IncrementCurrentGenerationCount(); } - - //and finally, call to increment the generation count for the generator content - this.IncrementCurrentGenerationCount(); } - private GeneratorNode HandleSameLevelGroupAddition( GeneratorNode firstChild, out int countAdded, NotifyCollectionChangedEventArgs e ) + private void HandleSameLevelGroupAddition( GeneratorNode firstChild, out int countAdded, NotifyCollectionChangedEventArgs e ) { - m_log.Assert( this, ( ( firstChild.Parent == null ) || ( firstChild.Parent is GroupGeneratorNode ) ), "parent of the node should be a GroupGeneratorNode" ); - - GeneratorNode newNodeChain = this.CreateGroupListFromCollection( e.NewItems, firstChild.Parent ); - - countAdded = 0; - if( newNodeChain != null ) + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_HandleSameLevelGroupAddition ) ) { - int chainLength; - GeneratorNodeHelper.EvaluateChain( newNodeChain, out countAdded, out chainLength ); + if( ( firstChild.Parent != null ) && !( firstChild.Parent is GroupGeneratorNode ) ) + { + this.TraceEvent( TraceEventType.Error, DataGridTraceEventId.CustomItemContainerGenerator_HandleSameLevelGroupAddition, DataGridTraceMessages.UnexpectedNode, DataGridTraceArgs.Node( firstChild.Parent ) ); + } - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( firstChild, 0, 0 ); //do not care about index. + var newNodeChain = this.CreateGroupListFromCollection( e.NewItems, firstChild.Parent ); - //Advance to the first "Group" node (skip the GroupHEaders) - while( !( nodeHelper.CurrentNode is GroupGeneratorNode ) ) + countAdded = 0; + if( newNodeChain != null ) { - if( !nodeHelper.MoveToNext() ) + int chainLength; + GeneratorNodeHelper.EvaluateChain( newNodeChain, out countAdded, out chainLength ); + + var nodeHelper = default( GeneratorNodeHelper ); + var insertAfter = false; + + // Instead of counting groups to insert the group chain, we may locate right away the GroupGeneratorNode that + // preceed the insertion point. This will give us a performance boost when there are lots of groups. + if( e.NewStartingIndex > 0 ) { - //if there are no items and no groups in the Group Node, then we will never find a GroupGeneratorNode... - //However, the structure of the group/headers/footers/group headers/groups footers makes it so - //that inserting before the last item (footer/group footer) will place the group at the appropriate location. - break; + IList groups; + + if( firstChild.Parent != null ) + { + var parentGroup = ( ( GroupGeneratorNode )firstChild.Parent ).CollectionViewGroup; + + groups = ( parentGroup != null ) ? parentGroup.Items : null; + } + else + { + groups = m_groupsCollection; + } + + if( ( groups != null ) && ( groups.Count > 0 ) ) + { + Debug.Assert( e.NewStartingIndex <= groups.Count ); + + var previousGroup = ( CollectionViewGroup )groups[ e.NewStartingIndex - 1 ]; + var previousGroupNode = default( GroupGeneratorNode ); + + if( m_groupNodeMappingCache.TryGetValue( previousGroup, out previousGroupNode ) ) + { + nodeHelper = new GeneratorNodeHelper( previousGroupNode, 0, 0 ); //do not care about index. + insertAfter = true; + } + } } - } - bool insertAfter = false; - //If there is 0 group in the parent group, then this loop will exit without executing the control block once... - for( int i = 0; i < e.NewStartingIndex; i++ ) - { - if( !nodeHelper.MoveToNext() ) + // We could not find the insertion point efficiently, use a fallback strategy. + if( nodeHelper == null ) { - insertAfter = true; + nodeHelper = new GeneratorNodeHelper( firstChild, 0, 0 ); //do not care about index. + + while( !( nodeHelper.CurrentNode is GroupGeneratorNode ) ) + { + if( !nodeHelper.MoveToNext() ) + { + //if there are no items and no groups in the Group Node, then we will never find a GroupGeneratorNode... + //However, the structure of the group/headers/footers/group headers/groups footers makes it so + //that inserting before the last item (footer/group footer) will place the group at the appropriate location. + break; + } + } + + //If there is 0 group in the parent group, then this loop will exit without executing the control block once... + for( int i = 0; i < e.NewStartingIndex; i++ ) + { + if( !nodeHelper.MoveToNext() ) + { + insertAfter = true; + } + } } - } - //if we are inserting past the end of the linked list level. - if( insertAfter ) - { - nodeHelper.InsertAfter( newNodeChain ); - } - else - { - //we are inserting in the middle of the list - nodeHelper.InsertBefore( newNodeChain ); - } + Debug.Assert( nodeHelper != null ); + //if we are inserting past the end of the linked list level. + if( insertAfter ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_HandleSameLevelGroupAddition, DataGridTraceMessages.GroupNodeAdded, DataGridTraceArgs.Node( newNodeChain ), DataGridTraceArgs.PreviousNode( nodeHelper.CurrentNode ), DataGridTraceArgs.ItemCount( countAdded ) ); + nodeHelper.InsertAfter( newNodeChain ); + } + else + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_HandleSameLevelGroupAddition, DataGridTraceMessages.GroupNodeAdded, DataGridTraceArgs.Node( newNodeChain ), DataGridTraceArgs.NextNode( nodeHelper.CurrentNode ), DataGridTraceArgs.ItemCount( countAdded ) ); + nodeHelper.InsertBefore( newNodeChain ); + } - //If the insertion point is the beginning, check that the node pointers are updated properly - if( ( e.NewStartingIndex == 0 ) && ( ( firstChild.Parent == null ) ) ) - { - if( m_startNode == m_firstItem ) + + //If the insertion point is the beginning, check that the node pointers are updated properly + if( ( e.NewStartingIndex == 0 ) && ( ( firstChild.Parent == null ) ) ) { - m_startNode = newNodeChain; + if( m_startNode == m_firstItem ) + { + m_startNode = newNodeChain; + } + + m_firstItem = newNodeChain; + + this.InvalidateNodeTree(); } - m_firstItem = newNodeChain; } - } - - return newNodeChain; } - private GeneratorNode HandleParentGroupAddition( GeneratorNode parent, out int countAdded, NotifyCollectionChangedEventArgs e ) + private void HandleParentGroupAddition( GeneratorNode parent, out int countAdded, NotifyCollectionChangedEventArgs e ) { - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( parent, 0, 0 ); //do not care about index (for now). + var nodeHelper = new GeneratorNodeHelper( parent, 0, 0 ); //do not care about index (for now). //start by moving to the first child... of the node (GroupHeaders node, most probably). if( !nodeHelper.MoveToChild( false ) ) - throw new DataGridInternalException( "Could not move to the child node to be removed.", m_dataGridControl ); + throw DataGridException.Create( "Could not move to the child node to be removed.", m_dataGridControl ); - return this.HandleSameLevelGroupAddition( nodeHelper.CurrentNode, out countAdded, e ); + this.HandleSameLevelGroupAddition( nodeHelper.CurrentNode, out countAdded, e ); } - private void HandleItemAddition( GeneratorNode node, NotifyCollectionChangedEventArgs e ) + private void HandleItemAddition( ItemsGeneratorNode node, NotifyCollectionChangedEventArgs e ) { - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( node, 0, 0 ); //index not important for now. - - node.AdjustItemCount( e.NewItems.Count ); - - ItemsGeneratorNode itemsNode = node as ItemsGeneratorNode; - if( itemsNode != null ) + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_HandleItemAddition, DataGridTraceArgs.Node( node ) ) ) { - itemsNode.AdjustLeafCount( e.NewItems.Count ); - this.OffsetDetails( itemsNode, e.NewStartingIndex, e.NewItems.Count ); - } - - //if the node is totally expanded - if( node.IsComputedExpanded ) - { - nodeHelper.ReverseCalculateIndex(); + var nodeHelper = new GeneratorNodeHelper( node, 0, 0 ); //index not important for now. + var itemCount = e.NewItems.Count; - //invalidate the indexes - this.IncrementCurrentGenerationCount(); + node.AdjustItemCount( itemCount ); + node.AdjustLeafCount( itemCount ); + this.OffsetDetails( node, e.NewStartingIndex, itemCount ); - int startIndex = nodeHelper.Index + e.NewStartingIndex; - GeneratorPosition addGenPos = this.GeneratorPositionFromIndex( startIndex ); + if( node.IsComputedExpanded ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_HandleItemAddition, DataGridTraceMessages.ItemAdded, DataGridTraceArgs.ItemCount( itemCount ) ); - //and send notification message - this.SendAddEvent( addGenPos, startIndex, e.NewItems.Count ); - } - else - { - //An item can be added in the source without the need to regenerate the containers, but still provoke a change to the realized containers' corresponding source index. - this.UpdateContainersIndex(); + this.IncrementCurrentGenerationCount(); + this.SendAddEvent( itemCount ); + } + else + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_HandleItemAddition, DataGridTraceMessages.CollapsedItemAdded, DataGridTraceArgs.ItemCount( itemCount ) ); + } } } private void HandleItemRemoveMoveReplace( ItemsGeneratorNode node, NotifyCollectionChangedEventArgs e ) { - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( node, 0, 0 ); //index not important for now. - nodeHelper.ReverseCalculateIndex(); + if( e.Action == NotifyCollectionChangedAction.Remove ) + { + node.AdjustItemCount( -e.OldItems.Count ); + node.AdjustLeafCount( -e.OldItems.Count ); + } - node.AdjustItemCount( -e.OldItems.Count ); - node.AdjustLeafCount( -e.OldItems.Count ); + var nodeStartIndex = e.OldStartingIndex; + var nodeEndIndex = nodeStartIndex + e.OldItems.Count - 1; + var detailCountToRemove = CustomItemContainerGenerator.ComputeDetailsCount( node, nodeStartIndex, nodeEndIndex ); + var detailCountBeforeRemovedItems = 0; - int nodeStartIndex = e.OldStartingIndex; - int nodeEndIndex = nodeStartIndex + e.OldItems.Count - 1; - int detailCountToRemove = CustomItemContainerGenerator.ComputeDetailsCount( node, nodeStartIndex, nodeEndIndex ); - int detailCountBeforeRemovedItems = 0; if( nodeStartIndex > 0 ) { detailCountBeforeRemovedItems = CustomItemContainerGenerator.ComputeDetailsCount( node, 0, nodeStartIndex - 1 ); } - int startIndex = nodeHelper.Index + e.OldStartingIndex + detailCountBeforeRemovedItems; - int endIndex = startIndex + detailCountToRemove + e.OldItems.Count - 1; + var removeCount = e.OldItems.Count + detailCountToRemove; + var replaceCount = ( e.Action == NotifyCollectionChangedAction.Replace ) ? e.NewItems.Count : 0; + var startIndex = -1; + var endIndex = -1; + + // We must memorize the range of items that we are going to remove before starting any action. + if( node.IsComputedExpanded ) + { + var nodeHelper = new GeneratorNodeHelper( node, 0, 0 ); //index not important for now. + nodeHelper.ReverseCalculateIndex(); - int removeCount = e.OldItems.Count + detailCountToRemove; - int replaceCount = ( e.Action == NotifyCollectionChangedAction.Replace ) ? e.NewItems.Count : 0; + startIndex = nodeHelper.Index + e.OldStartingIndex + detailCountBeforeRemovedItems; + endIndex = startIndex + detailCountToRemove + e.OldItems.Count - 1; + } //Remove the details from the ItemsGeneratorNode and re-index the other details appropriatly. this.RemoveDetails( node, nodeStartIndex, nodeEndIndex, replaceCount ); - GeneratorPosition removeGenPos = this.GetSafeGeneratorPositionFromIndex( startIndex ); - //Try to remap the old item for detail remapping (will do nothing if item has no details ) - foreach( object oldItem in e.OldItems ) + foreach( var oldItem in e.OldItems ) { this.QueueDetailItemForRemapping( oldItem ); } - bool needsUpdateToIndexes = true; - //if the node is totally expanded + var raiseEvent = false; + var removedContainers = default( List ); + + // Remove the matching realized containers. if( node.IsComputedExpanded ) { - needsUpdateToIndexes = false; - List removedContainers = new List(); - int genRemCount = this.RemoveGeneratedItems( startIndex, endIndex, removedContainers ); + raiseEvent = true; + removedContainers = new List(); - this.IncrementCurrentGenerationCount(); + Debug.Assert( ( startIndex >= 0 ) && ( endIndex >= 0 ) ); - this.SendRemoveEvent( removeGenPos, startIndex, removeCount, genRemCount, removedContainers ); + this.RemoveGeneratedItems( startIndex, endIndex, removedContainers ); } - //then, based on the action that was performed (move, replace or remove) - switch( e.Action ) + if( e.Action == NotifyCollectionChangedAction.Move ) { - case NotifyCollectionChangedAction.Move: - this.OffsetDetails( node, e.NewStartingIndex, e.NewItems.Count ); - this.HandleItemMoveRemoveReplaceHelper( node, e, nodeHelper.Index ); - break; - - case NotifyCollectionChangedAction.Replace: - this.HandleItemMoveRemoveReplaceHelper( node, e, nodeHelper.Index ); - break; - - case NotifyCollectionChangedAction.Remove: - if( needsUpdateToIndexes ) - { - //An item can be removed from the source without the need to regenerate the containers, - //but still provoke a change to the realized containers' corresponding source index. - this.UpdateContainersIndex(); - } - break; - - case NotifyCollectionChangedAction.Add: - case NotifyCollectionChangedAction.Reset: - DataGridException.ThrowSystemException( "Add or Reset not supported at the moment on groups.", typeof( NotSupportedException ), m_dataGridControl.Name ); - break; + this.OffsetDetails( node, e.NewStartingIndex, e.NewItems.Count ); } - } - - private void HandleItemMoveRemoveReplaceHelper( ItemsGeneratorNode node, NotifyCollectionChangedEventArgs e, int nodeIndex ) - { - node.AdjustItemCount( e.NewItems.Count ); - node.AdjustLeafCount( e.NewItems.Count ); + if( raiseEvent ) + { + Debug.Assert( removedContainers != null ); - this.IncrementCurrentGenerationCount(); + this.IncrementCurrentGenerationCount(); + this.SendRemoveEvent( removeCount, removedContainers ); - //this is used to notify any Master Generator that it must update its content's status (UpdateGenPosToIndexList) - this.SendAddEvent( new GeneratorPosition( -1, 1 ), nodeIndex + e.NewStartingIndex, e.NewItems.Count ); + switch( e.Action ) + { + case NotifyCollectionChangedAction.Move: + case NotifyCollectionChangedAction.Replace: + { + this.SendAddEvent( e.NewItems.Count ); + } + break; + + case NotifyCollectionChangedAction.Remove: + // There is nothing to do. + break; + + case NotifyCollectionChangedAction.Add: + case NotifyCollectionChangedAction.Reset: + throw DataGridException.Create( "Add or Reset not supported at the moment on groups.", m_dataGridControl ); + } + } } - private void UpdateContainersIndex() + private void HandleHeadersFootersAddition( IEnumerable nodes, NotifyCollectionChangedEventArgs e ) { - DataGridCollectionView collectionView = m_collectionView.SourceCollection as DataGridCollectionView; - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); - int currentIndex = -1; - int offset = 0; - int sourceItemIndex; + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_HandleHeadersFootersAddition ) ) + { + var itemCount = e.NewItems.Count; + var notify = false; + + foreach( var node in nodes ) + { + node.AdjustItemCount( itemCount ); + notify = notify || node.IsComputedExpanded; + } + + if( notify ) + { + this.IncrementCurrentGenerationCount(); + + this.SendResetEvent(); + } + else + { + //There is no need to regenerate the containers. However, we still need to update the realized containers source index. + this.UpdateContainersIndex(); + } + } + } - foreach( object item in m_genPosToItem ) + private void HandleHeadersFootersRemoveMoveReplace( IEnumerable nodes, NotifyCollectionChangedEventArgs e ) + { + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_HandleHeadersFootersRemoveMoveReplace ) ) { - currentIndex++; + Debug.Assert( e.OldItems != null ); - //If the item is not found, it means it belongs to a detail grid, no need to process it. - if( nodeHelper.FindItem( item ) == -1 ) - continue; + var itemCount = ( ( e.NewItems != null ) ? e.NewItems.Count : 0 ) - e.OldItems.Count; + var notify = false; - //If we're not on a ItemsGeneratorNode, it means we are not on a DataRow, so no need to process it (all ItemIndex == -1 in this case). - ItemsGeneratorNode itemsNode = nodeHelper.CurrentNode as ItemsGeneratorNode; - if( itemsNode == null ) + foreach( var node in nodes ) { - offset = 0; - continue; + node.AdjustItemCount( itemCount ); + + if( node.IsComputedExpanded ) + { + notify = true; + + var parentGroup = node.Parent as GroupGeneratorNode; + + foreach( var item in e.OldItems ) + { + var targetItem = ( parentGroup != null ) ? new GroupHeaderFooterItem( parentGroup.CollectionViewGroup, item ) : item; + + this.RemoveGeneratedItems( node, targetItem, null ); + } + } } - //If we have a DataGridCollectionView, let's get the sorted index from it in case there are details expanded. - if( collectionView != null ) + if( notify ) { - sourceItemIndex = collectionView.GetGlobalSortedIndexFromDataItem( item ); + this.IncrementCurrentGenerationCount(); + + this.SendResetEvent(); } - //If not a DGCV, it means there are no details, so this will work fine. else { - if( offset == 0 ) + //There is no need to regenerate the containers. However, we still need to update the realized containers source index. + this.UpdateContainersIndex(); + } + } + } + + private void UpdateContainersIndex() + { + if( ( m_startNode == null ) || ( m_genPosToItem.Count <= 0 ) ) + return; + + var collectionView = m_collectionView.SourceCollection as DataGridCollectionView; + if( collectionView != null ) + { + for( int i = 0; i < m_genPosToItem.Count; i++ ) + { + // If we're not on an ItemsGeneratorNode, it means we are not on a DataRow, so no need to process it (all ItemIndex == -1 in this case). + if( !( m_genPosToNode[ i ] is ItemsGeneratorNode ) ) + continue; + + // There is no need to find the node or the item within the node since it should match the CollectionView. + var sourceIndex = collectionView.GetGlobalSortedIndexFromDataItem( m_genPosToItem[ i ] ); + + DataGridVirtualizingPanel.SetItemIndex( m_genPosToContainer[ i ], sourceIndex ); + } + } + else + { + var nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + + for( int i = 0; i < m_genPosToItem.Count; i++ ) + { + // If we're not on an ItemsGeneratorNode, it means we are not on a DataRow, so no need to process it (all ItemIndex == -1 in this case). + var node = m_genPosToNode[ i ] as ItemsGeneratorNode; + if( node == null ) + continue; + + int offset = -1; + + if( nodeHelper.FindNode( node ) && ( nodeHelper.FindItem( m_genPosToItem[ i ] ) >= 0 ) ) { - //This will make sure we get the right index in case the group is patially scrolled. - offset = itemsNode.IndexOf( item ); + offset = node.IndexOf( m_genPosToItem[ i ] ); } - sourceItemIndex = nodeHelper.SourceDataIndex + offset++; + + // If not a DGCV, it means there are no details, so this will work fine. + var sourceIndex = ( offset >= 0 ) + ? nodeHelper.SourceDataIndex + offset + : -1; + + DataGridVirtualizingPanel.SetItemIndex( m_genPosToContainer[ i ], sourceIndex ); } - DataGridVirtualizingPanel.SetItemIndex( m_genPosToContainer[ currentIndex ], sourceItemIndex ); } } @@ -5139,35 +5086,23 @@ namespace Xceed.Wpf.DataGrid if( ( node.Details == null ) || ( node.Details.Count == 0 ) ) return; - int detailsCount = node.Details.Count; - //first, create an array that will contain the keys for all the expanded details from the ItemsGeneratorNode - int[] keys = new int[ detailsCount ]; + var detailsCount = node.Details.Count; + var keys = new int[ detailsCount ]; node.Details.Keys.CopyTo( keys, 0 ); - //sort the array, this will prevent any operation that will duplicate keys in the dictionary. Array.Sort( keys ); - //loop from the end of the sorted array to the beginning. to ensuyre for( int i = detailsCount - 1; i >= 0; i-- ) { - int key = keys[ i ]; - - //only process the key if it is in the processed range + var key = keys[ i ]; if( key >= startIndex ) { List details; - if( node.Details.TryGetValue( key, out details ) ) - { - m_log.WriteLine( this, "details.Offset for Add - IN" + node.GetHashCode().ToString() + "- Di" + key.ToString() + " - new Di" + ( key + addOffset ).ToString() ); + if( !node.Details.TryGetValue( key, out details ) ) + throw DataGridException.Create( "Key not found in Details dictionary.", m_dataGridControl ); - node.Details.Remove( key ); - node.Details.Add( key + addOffset, details ); - } - else - { - //Key not found in the dictionary, something wrong is going on. - throw new DataGridInternalException( "Key not found in Details dictionary.", m_dataGridControl ); - } + node.Details.Remove( key ); + node.Details.Add( key + addOffset, details ); } } } @@ -5177,21 +5112,19 @@ namespace Xceed.Wpf.DataGrid if( ( node.Details == null ) || ( node.Details.Count == 0 ) ) return; - int removeCount = nodeEndIndex - nodeStartIndex + 1 - replaceCount; + var removeCount = nodeEndIndex - nodeStartIndex + 1 - replaceCount; //Note: If a replace was invoked, replace count will be greater than 0, and will be used to properly re-offset the //details beyond the initial remove range. //Note2: for the case of a move or remove, the replace count must remain 0, so that the other details are correctly offseted. - //first, create an array that will contain the keys for all the expanded details from the ItemsGeneratorNode - int[] keys = new int[ node.Details.Count ]; + var keys = new int[ node.Details.Count ]; node.Details.Keys.CopyTo( keys, 0 ); - //sort the array, this will prevent any operation that will duplicate keys in the dictionary. Array.Sort( keys ); - //cycle through all of the old items - int countDetailsRemoved = 0; + var countDetailsRemoved = 0; + foreach( int key in keys ) { //if the key is below the remove range, do not do anything with the dictionary entry @@ -5203,14 +5136,12 @@ namespace Xceed.Wpf.DataGrid if( node.Details.TryGetValue( key, out details ) ) { //sum them - foreach( DetailGeneratorNode detailNode in details ) + foreach( var detailNode in details ) { countDetailsRemoved += detailNode.ItemCount; } details.Clear(); //note: detail generators will be "closed" by another section of code (Remap floating details). - m_log.WriteLine( this, "details.Remove - IN" + node.GetHashCode().ToString() + " - Di" + key.ToString() ); - node.Details.Remove( key ); if( node.Details.Count == 0 ) @@ -5221,7 +5152,7 @@ namespace Xceed.Wpf.DataGrid else { //Key not found in the dictionary, something wrong is going on. - throw new DataGridInternalException( "Key not found in Details dictionary within the remove range.", m_dataGridControl ); + throw DataGridException.Create( "Key not found in Details dictionary within the remove range.", m_dataGridControl ); } } //If the key is above the remove range, re-key it appropriatly. @@ -5230,15 +5161,13 @@ namespace Xceed.Wpf.DataGrid List details; if( node.Details.TryGetValue( key, out details ) ) { - m_log.WriteLine( this, "details.offset for remove - IN" + node.GetHashCode().ToString() + "- Di" + key.ToString() + " - new Di" + ( key - removeCount ).ToString() ); - node.Details.Remove( key ); node.Details.Add( key - removeCount, details ); } else { //Key not found in the dictionary, something wrong is going on. - throw new DataGridInternalException( "Key not found in Details dictionary above the remove range.", m_dataGridControl ); + throw DataGridException.Create( "Key not found in Details dictionary above the remove range.", m_dataGridControl ); } } } @@ -5262,7 +5191,7 @@ namespace Xceed.Wpf.DataGrid List details; if( node.Details.TryGetValue( i, out details ) ) { - foreach( DetailGeneratorNode detailNode in details ) + foreach( var detailNode in details ) { detailCount += detailNode.ItemCount; } @@ -5273,313 +5202,584 @@ namespace Xceed.Wpf.DataGrid return detailCount; } - private void HandleItemReset( GeneratorNode node ) + private void HandleItemReset( ItemsGeneratorNode node ) { - //these 4 variables will hold the content for the Removal and the re-addition of the items. - int countGeneratedRemoved; - GeneratorPosition itemGenPos; - - List removedContainers = new List(); - - //by definition, items from a node are contiguous... - itemGenPos = this.FindFirstRealizedItemsForNode( node ); - int removeIndex = ( itemGenPos.Offset == 0 ) ? m_genPosToIndex[ itemGenPos.Index ] : -1; - countGeneratedRemoved = this.RemoveGeneratedItems( node, removedContainers ); + Debug.Assert( node != null ); - // ensure that the mapping of the details to that node are removed! - ItemsGeneratorNode itemsNode = node as ItemsGeneratorNode; - if( ( itemsNode != null ) && ( itemsNode.Details != null ) ) + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_HandleItemReset ) ) { - int detailCount = 0; - foreach( List detailList in itemsNode.Details.Values ) + var oldItems = new List(); + var newItems = new IListWrapper( node.Items ); + var oldItemsFound = new HashSet(); + + for( int i = 0; i < m_genPosToNode.Count; i++ ) { - foreach( DetailGeneratorNode detailNode in detailList ) + var currentNode = m_genPosToNode[ i ]; + var currentItem = default( object ); + + if( currentNode == node ) { - detailCount += detailNode.ItemCount; + currentItem = m_genPosToItem[ i ]; + } + // Since some details of an unrealized item may be realized, we need to consider the unrealized + // item as if it was realized or the details containers may not be properly ordered in the + // internal data structure. + else if( currentNode is DetailGeneratorNode ) + { + currentItem = ( ( DetailGeneratorNode )currentNode ).DetailContext.ParentItem; + } + else + { + continue; } - } - m_log.WriteLine( this, "details.Clear - IN" + itemsNode.GetHashCode().ToString() ); + Debug.Assert( currentItem != null ); + if( !oldItemsFound.Add( currentItem ) ) + continue; - itemsNode.Details.Clear(); - itemsNode.Details = null; + oldItems.Add( currentItem ); + } - node.AdjustItemCount( -detailCount ); - } + ICollection itemsRemoved; + ICollection itemsMoved; - //send the removal notification to the panel... - this.IncrementCurrentGenerationCount(); + if( this.IsDataVirtualized( node ) ) + { + // Since the items collection is doning data virtualization, we do not want to enumerate items. + // Instead, we will simply remove the containers that were linked to old items to requery the items + // on demand. + itemsRemoved = new HashSet( oldItems ); + itemsMoved = new HashSet(); + } + else + { + itemsRemoved = new HashSet(); + itemsMoved = new HashSet(); - if( countGeneratedRemoved > 0 ) - { - this.SendRemoveEvent( itemGenPos, removeIndex, 0, countGeneratedRemoved, removedContainers ); + // Since the old items collection contains only items that are realized, we must be aware + // that the collections for the items moved or removed are for realized items only. Other + // items may have moved or were removed and we are not aware of it. + CustomItemContainerGenerator.FindChanges( oldItems, newItems, null, itemsRemoved, itemsMoved ); + } + + this.ApplyItemChanges( node, newItems, itemsRemoved, itemsMoved ); } } - private void HandleHeaderFooterRemove( HeadersFootersGeneratorNode node, NotifyCollectionChangedEventArgs e ) + private void HandleGlobalItemsReset() { - bool itemsRemoved = false; - - node.AdjustItemCount( -e.OldItems.Count ); - - //if the node is totally expanded - if( node.IsComputedExpanded ) + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_HandleGlobalItemsReset ) ) { - GroupGeneratorNode parentGroup = node.Parent as GroupGeneratorNode; + this.ForceReset = false; + + if( this.IsHandlingGlobalItemsResetLocally ) + { + this.TraceEvent( TraceEventType.Warning, DataGridTraceEventId.CustomItemContainerGenerator_HandleGlobalItemsReset, DataGridTraceMessages.CannotProcessOnReset ); + return; + } - int removeGenPosIndex; - int removeIndex; + if( m_startNode == null ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_HandleGlobalItemsReset, DataGridTraceMessages.EmptyTree ); + return; + } - foreach( object item in e.OldItems ) + using( this.SetIsHandlingGlobalItemsResetLocally() ) { - object realItem = ( parentGroup != null ) - ? new GroupHeaderFooterItem( parentGroup.CollectionViewGroup, item ) - : item; + this.RemoveAllGeneratedItems(); + //No need to clean any more Master/Detail stuff, effectivelly, the call to ClearItems() below will clean the nodes themselves... + //generator will then be able to remap. - removeGenPosIndex = m_genPosToItem.IndexOf( realItem ); - GeneratorPosition removeGenPos; - // If the value is -1, it means the Header/Footer was not realized when the remove occured. - if( removeGenPosIndex != -1 ) - { - removeIndex = m_genPosToIndex[ removeGenPosIndex ]; - removeGenPos = new GeneratorPosition( removeGenPosIndex, 0 ); - } - else + //if there are items to start with!!! + if( m_firstItem != null ) { - //Since there is no way to get the item's index from the list of generated items, then - //compute it based on the node's index and the event args parameters. + m_dataGridControl.SaveDataGridContextState( m_dataGridContext, true, int.MaxValue ); - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( node, 0, 0 ); - nodeHelper.ReverseCalculateIndex(); + //requeue all opened details for remapping! + foreach( object item in m_masterToDetails.Keys ) + { + this.QueueDetailItemForRemapping( item ); + } - removeIndex = nodeHelper.Index + e.OldStartingIndex; + //then clear the items nodes + this.ClearItems(); + this.RefreshGroupsCollection(); - removeGenPos = this.GeneratorPositionFromIndex( removeIndex ); - } + //increment the generation count... to ensure that further calls to the index based functions are not messed up. + this.IncrementCurrentGenerationCount(); - List removedContainers = new List(); - this.RemoveGeneratedItems( node, realItem, removedContainers ); + //Note: There is no need to Clear the recyclingManager since this only represents a reset of the Items (not the headers and footers nodes) + //and that the list of containers to be recycled is not "invalidated" - this.SendRemoveEvent( removeGenPos, removeIndex, 1, removedContainers.Count, removedContainers ); - itemsRemoved = true; - } + } - this.IncrementCurrentGenerationCount( itemsRemoved ); + this.SendResetEvent(); + } } } - private void HandleHeaderFooterReplace( HeadersFootersGeneratorNode node, NotifyCollectionChangedEventArgs e ) - { - //add immediately the number of new items to the "parent" node since the function call right below will remove the number of old items. - node.AdjustItemCount( e.NewItems.Count ); - - this.HandleHeaderFooterRemove( node, e ); - } - - private GeneratorPosition FindFirstRealizedItemsForNode( GeneratorNode referenceNode ) + private void ApplyItemChanges( + ItemsGeneratorNode node, + IList newItems, + ICollection itemsRemoved, + ICollection itemsMoved ) { - GeneratorPosition retval = new GeneratorPosition( -1, 1 ); - int genPosCounter = -1; + Debug.Assert( node != null ); + Debug.Assert( newItems != null ); + Debug.Assert( itemsRemoved != null ); + Debug.Assert( itemsMoved != null ); - List nodesAccepted = new List(); - nodesAccepted.Add( referenceNode ); + // IMPORTANT: The items removed and moved collection contains realized items that have moved + // or have been removed. It is possible that some of the items that were not + // realized have moved or have been removed and we are unaware of it. We must + // consider this possibility in the following algorithm. - //if there are details for the reference node - ItemsGeneratorNode itemsNode = referenceNode as ItemsGeneratorNode; - if( ( itemsNode != null ) && ( itemsNode.Details != null ) ) - { - foreach( List details in itemsNode.Details.Values ) - { - foreach( DetailGeneratorNode detailNode in details ) - { - nodesAccepted.Add( detailNode ); - } - } - } + var detailEntries = node.Details; + var detailNodes = new HashSet(); + var detailNodesByItem = new Dictionary>(); + var isDataVirtualized = this.IsDataVirtualized( node ); - for( int i = 0; i < m_genPosToNode.Count; i++ ) + // The first thing to do is to remove all details that are linked to items that are not in the final result set. + if( detailEntries != null ) { - GeneratorNode node = m_genPosToNode[ i ]; + var itemCount = 0; - //For master/detail, I have to decouple the index to genPos relationship (because of detail rows, possibly messing up with generated items. - genPosCounter++; - - //if the node currently observed is my reference node, get it's computed generator position - if( nodesAccepted.Contains( node ) ) + foreach( var detailEntry in detailEntries.ToList() ) { - retval = new GeneratorPosition( genPosCounter, 0 ); - break; - } - } - - return retval; - } + var i = 0; + var detailList = detailEntry.Value; - private void HandleGlobalItemsReset() - { - m_log.Assert( this, !this.IsHandlingGlobalItemsResetLocally, "Generator is already processing a HandleGlobalItemReset or CleanupGenerator" ); + while( i < detailList.Count ) + { + var detailNode = detailList[ i ]; + var masterItem = detailNode.DetailContext.ParentItem; - if( this.IsHandlingGlobalItemsResetLocally ) - return; + // Since the items removed collection is for realized item only, we must take a look + // at the final result set in case the item was unrealized and removed. + if( isDataVirtualized || itemsRemoved.Contains( masterItem ) || !newItems.Contains( masterItem ) ) + { + itemCount += detailNode.ItemCount; + detailList.RemoveAt( i ); - if( m_startNode == null ) - { - m_log.WriteLine( this, "No starting node in HandleGlobalItemsReset." ); - return; - } + // Put the detail aside and close it properly later. + this.RemoveGeneratedItems( detailNode, null ); + this.QueueDetailItemForRemapping( masterItem ); + } + else + { + // Keep a list of active detail nodes and their order. We will need those later in the algorithm. + detailNodes.Add( detailNode ); - using( m_log.BeginBlock( this, null ) ) - using( this.SetIsHandlingGlobalItemsResetLocally() ) - { - this.RemoveAllGeneratedItems(); + var detailNodesList = default( List ); + if( !detailNodesByItem.TryGetValue( masterItem, out detailNodesList ) ) + { + detailNodesList = new List( 1 ); + detailNodesByItem.Add( masterItem, detailNodesList ); + } - //No need to clean any more Master/Detail stuff, effectivelly, the call to ClearItems() below will clean the nodes themselves... - //generator will then be able to remap. + Debug.Assert( detailNodesList != null ); + detailNodesList.Add( detailNode ); - //if there are items to start with!!! - if( m_firstItem != null ) - { - m_dataGridControl.SaveDataGridContextState( m_dataGridContext, true, int.MaxValue ); + i++; + } + } - //requeue all opened details for remapping! - foreach( object item in m_masterToDetails.Keys ) + if( detailList.Count <= 0 ) { - this.QueueDetailItemForRemapping( item ); + detailEntries.Remove( detailEntry.Key ); } + } - //then clear the items nodes - this.ClearItems(); - this.RefreshGroupsCollection(); - - //increment the generation count... to ensure that further calls to the index based functions are not messed up. - this.IncrementCurrentGenerationCount(); - - //Note: There is no need to Clear the recyclingManager since this only represents a reset of the Items (not the headers and footers nodes) - //and that the list of containers to be recycled is not "invalidated" - + if( detailEntries.Count <= 0 ) + { + node.Details = null; } - this.SendResetEvent(); + node.AdjustItemCount( -itemCount ); } - } - - internal void EnsureNodeTreeCreated() - { - //This is done to ensure that any public interface function called get an "up to date" generator content when being accessed. - // No reentrency is allowed for this method - // to avoid any problem. - if( this.IsEnsuringNodeTreeCreated ) - return; - - using( this.SetIsEnsuringNodeTreeCreated() ) + // The next thing to do is to remove the containers for the realized items that were removed. + if( itemsRemoved.Count > 0 ) { - if( m_startNode == null ) + for( int i = m_genPosToItem.Count - 1; i >= 0; i-- ) { - m_log.WriteLine( this, "EnsureNodeTreeCreated - new tree" ); + if( !itemsRemoved.Contains( m_genPosToItem[ i ] ) ) + continue; - int addCount; + this.RemoveGeneratedItem( i, null ); + } + } - this.UpdateHeaders( m_dataGridContext.Headers ); - this.SetupInitialItemsNodes( out addCount ); - this.UpdateFooters( m_dataGridContext.Footers ); + // Now that everything that needed to be removed was removed, we will repair the collection + // that is used as a link between items and detail nodes. + if( detailNodes.Count > 0 ) + { + Debug.Assert( detailEntries != null ); + Debug.Assert( detailEntries == node.Details ); + Debug.Assert( !isDataVirtualized ); - //This is to ensure that the RecyclingManager will consider this generator with regards to RefCount - //(refcount is used to determine when the list of container from the RecyclingManager needs to be removed) - m_dataGridContext.RecyclingManager.AddRef( this ); + detailEntries.Clear(); - this.IncrementCurrentGenerationCount(); - } - else if( m_firstItem == null ) + for( int i = 0; i < newItems.Count; i++ ) { - this.HandleItemsRecreation(); - } - - m_dataGridControl.RestoreDataGridContextState( m_dataGridContext ); - } - } + var masterItem = newItems[ i ]; + var detailNodesList = default( List ); - private void HandleItemsRecreation() - { - //Then, since its a Reset, recreates the Items nodes. - int resetAddCount; - GeneratorNode addNode = this.SetupInitialItemsNodes( out resetAddCount ); + if( detailNodesByItem.TryGetValue( masterItem, out detailNodesList ) ) + { + detailNodesByItem.Remove( masterItem ); + detailEntries.Add( i, detailNodesList ); + } + } - if( addNode != null ) - { - this.IncrementCurrentGenerationCount(); + Debug.Assert( ( detailNodesByItem.Count == 0 ), "The detail nodes should have been reinserted properly." ); } - } - - private void UpdateGenPosToIndexList() - { - this.ValidateIndexOrder( "Before" ); - - //after the modification to have the item count stored "locally" in the DetailGeneratorNodes, - //it becomes important to have the nodes updated when the layout of the items changes. - foreach( var detailNode in this.GetDetailGeneratorNodes() ) + else { - detailNode.UpdateItemCount(); + Debug.Assert( ( detailEntries == null ) || ( detailEntries.Count == 0 ) ); + Debug.Assert( node.Details == null ); } - if( m_startNode != null ) + // The next thing to do is to reorder the containers within the internal data structure so it match + // the ordering of the realized items that have moved. + if( itemsMoved.Count > 0 ) { - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); //index is 0, since i'm beginning at the start - //(and I want to reindex the whole list) + Debug.Assert( !isDataVirtualized ); - DetailGeneratorNode cachedDetailNode = null; - int cachedDetailNodeIndex = -1; - int previousDetailIndex = -1; + var insertionIndex = default( int? ); + var itemGenPosEntries = new Dictionary(); + var detailGenPosEntries = new Dictionary>>(); - //loop through the realized items. By design they are present sequentially in the linked list, so I do not need to reset the GeneratorNodeHelper - for( int i = 0; i < m_genPosToItem.Count; i++ ) + // Remove the entries within the data structure that are linked to the current node or one of its detail. { - object item = m_genPosToItem[ i ]; + var i = 0; - DetailGeneratorNode detailNode = m_genPosToNode[ i ] as DetailGeneratorNode; - if( detailNode == null ) + while( i < m_genPosToNode.Count ) { - //find the Item - int tmpIndex = nodeHelper.FindItem( item ); - if( tmpIndex != -1 ) + var currentNode = m_genPosToNode[ i ]; + + // We have found a container that is linked to one of the data item. + if( currentNode == node ) { - //set the Index (new) for the item - ItemsGeneratorNode itemsNode = nodeHelper.CurrentNode as ItemsGeneratorNode; - if( itemsNode != null ) + itemGenPosEntries.Add( m_genPosToItem[ i ], m_genPosToContainer[ i ] ); + } + // We have found a container that is part of a detail that is linked to one of the data item. + else if( detailNodes.Contains( currentNode ) ) + { + var detailInfos = default( IList> ); + + if( !detailGenPosEntries.TryGetValue( currentNode, out detailInfos ) ) { - tmpIndex = nodeHelper.Index + itemsNode.IndexOf( item ); + detailInfos = new List>(); + detailGenPosEntries.Add( currentNode, detailInfos ); } - m_genPosToIndex[ i ] = tmpIndex; + Debug.Assert( detailInfos != null ); + detailInfos.Add( new Tuple( m_genPosToItem[ i ], m_genPosToContainer[ i ] ) ); } + // The container as nothing to do with the node we are looking for or one of its detail. else { - m_log.WriteLine( this, CustomItemContainerGenerator.FormatObjectId( "# UpdateGenPosToIndexList - item not found D", item ) ); - - //a possible fix for this is to set the index of the "not found" element to the same index as previous item in the generated list... - m_genPosToIndex[ i ] = ( i > 0 ) ? m_genPosToIndex[ i - 1 ] : 0; + i++; + continue; + } - //item is not in the linked list... there is a problem, throw. - //throw new DataGridInternalException(); + // Remove the entries from the internal data structure. + this.GenPosArraysRemoveAt( i ); + // Keep a reference on the first location a removal occurred. + if( !insertionIndex.HasValue ) + { + insertionIndex = i; } } - else //else is detailNode != null + } + + // We must reinsert all entries that have been removed in the last step in appropriate order. + if( insertionIndex.HasValue ) + { + var index = insertionIndex.Value; + + for( int i = 0; i < newItems.Count; i++ ) { - if( cachedDetailNode != detailNode ) + var currentItem = newItems[ i ]; + var currentContainer = default( DependencyObject ); + + if( itemGenPosEntries.TryGetValue( currentItem, out currentContainer ) ) + { + itemGenPosEntries.Remove( currentItem ); + + // The value inserted as the index is not important and will be updated at the last step of the algorithmn. + m_genPosToContainer.Insert( index, currentContainer ); + m_genPosToIndex.Insert( index, int.MinValue ); + m_genPosToItem.Insert( index, currentItem ); + m_genPosToNode.Insert( index, node ); + + index++; + } + + if( ( detailEntries != null ) && ( detailEntries.Count > 0 ) ) { - cachedDetailNodeIndex = this.FindGlobalIndexForDetailNode( detailNode ); - cachedDetailNode = detailNode; - previousDetailIndex = -1; + var detailNodesList = default( List ); + + if( detailEntries.TryGetValue( i, out detailNodesList ) && ( detailNodesList != null ) ) + { + foreach( var detailNode in detailNodesList ) + { + var detailInfos = default( IList> ); + if( !detailGenPosEntries.TryGetValue( detailNode, out detailInfos ) ) + continue; + + detailGenPosEntries.Remove( detailNode ); + + foreach( var detailInfo in detailInfos ) + { + // The value inserted as the index is not important and will be updated at the last step of the algorithmn. + m_genPosToContainer.Insert( index, detailInfo.Item2 ); + m_genPosToIndex.Insert( index, int.MinValue ); + m_genPosToItem.Insert( index, detailInfo.Item1 ); + m_genPosToNode.Insert( index, detailNode ); + + index++; + } + } + } } - int detailIndex = detailNode.DetailGenerator.IndexFromRealizedItem( item, previousDetailIndex + 1, out previousDetailIndex ); - m_genPosToIndex[ i ] = cachedDetailNodeIndex + detailIndex; } - } //end for() + } + + Debug.Assert( ( itemGenPosEntries.Count == 0 ), "The containers should have been reinserted properly." ); + Debug.Assert( ( detailGenPosEntries.Count == 0 ), "The detail containers should have been reinserted properly." ); } - this.ValidateIndexOrder( "After" ); + // The last thing to do is to update the indexes and raise a notification. + this.IncrementCurrentGenerationCount(); + this.SendResetEvent(); + } + + private void ApplyDetailChanges( + DetailGeneratorNode node, + IList newContainers, + ICollection containersRemoved, + ICollection containersMoved ) + { + Debug.Assert( node != null ); + Debug.Assert( newContainers != null ); + Debug.Assert( containersRemoved != null ); + Debug.Assert( containersMoved != null ); + + // The first thing to do is to remove the containers for the realized items that were removed. + if( containersRemoved.Count > 0 ) + { + for( int i = m_genPosToContainer.Count - 1; i >= 0; i-- ) + { + if( !containersRemoved.Contains( m_genPosToContainer[ i ] ) ) + continue; + + this.RemoveGeneratedItem( i, null ); + } + } + + // The next thing to do is to reorder the containers within the internal data structure so it match + // the ordering of the realized containers that have moved. + if( containersMoved.Count > 0 ) + { + var insertionIndex = default( int? ); + var entries = new Dictionary(); + + // Remove the entries within the data structure that are linked to the detail node. + { + var i = 0; + + while( i < m_genPosToNode.Count ) + { + var currentNode = m_genPosToNode[ i ]; + + // We have found a container that is linked to the desired node. + if( currentNode == node ) + { + entries.Add( m_genPosToContainer[ i ], m_genPosToItem[ i ] ); + + // Remove the entries from the internal data structure. + this.GenPosArraysRemoveAt( i ); + + // Keep a reference on the first location a removal occurred. + if( !insertionIndex.HasValue ) + { + insertionIndex = i; + } + } + // The container as nothing to do with the node we are looking. + else + { + i++; + } + } + } + + // We must reinsert all entries that have been removed in the last step in appropriate order. + if( insertionIndex.HasValue ) + { + var index = insertionIndex.Value; + + for( int i = 0; i < newContainers.Count; i++ ) + { + var currentContainer = newContainers[ i ]; + var currentItem = default( object ); + + if( entries.TryGetValue( currentContainer, out currentItem ) ) + { + entries.Remove( currentContainer ); + + // The value inserted as the index is not important and will be updated at the last step of the algorithmn. + m_genPosToContainer.Insert( index, currentContainer ); + m_genPosToIndex.Insert( index, int.MinValue ); + m_genPosToItem.Insert( index, currentItem ); + m_genPosToNode.Insert( index, node ); + + index++; + } + } + } + + Debug.Assert( ( entries.Count == 0 ), "The containers should have been reinserted properly." ); + } + + // The last thing to do is to update the indexes and raise a notification. + this.IncrementCurrentGenerationCount(); + this.SendResetEvent(); + } + + internal void EnsureNodeTreeCreated() + { + //This is done to ensure that any public interface function called get an "up to date" generator content when being accessed. + + // No reentrency is allowed for this method + // to avoid any problem. + if( this.IsNodeTreeValid || this.IsEnsuringNodeTreeCreated ) + return; + + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_EnsureNodeTreeCreated ) ) + using( this.SetIsEnsuringNodeTreeCreated() ) + { + if( m_startNode == null ) + { + int addCount; + + this.UpdateHeaders( m_dataGridContext.Headers ); + this.SetupInitialItemsNodes( out addCount ); + this.UpdateFooters( m_dataGridContext.Footers ); + + this.IncrementCurrentGenerationCount(); + } + else if( m_firstItem == null ) + { + this.HandleItemsRecreation(); + } + + this.EnsureDetailsNodeTreeCreated(); + this.RemapFloatingDetails(); + + m_dataGridControl.RestoreDataGridContextState( m_dataGridContext ); + } + + // The current method will need to be called again. The data source is most probably not set yet. + if( ( m_startNode == null ) || ( m_firstItem == null ) || ( m_floatingDetails.Count != 0 ) ) + { + this.InvalidateNodeTree(); + } + } + + private void EnsureDetailsNodeTreeCreated() + { + if( m_masterToDetails.Count == 0 ) + return; + + Debug.Assert( this.IsEnsuringNodeTreeCreated, "The method EnsureDetailsNodeTreeCreated should have been called from EnsureNodeTreeCreated." ); + + foreach( var generator in this.GetDetailGenerators().ToList() ) + { + generator.EnsureNodeTreeCreated(); + } + } + + private void HandleItemsRecreation() + { + //Then, since its a Reset, recreates the Items nodes. + int resetAddCount; + + var addNode = this.SetupInitialItemsNodes( out resetAddCount ); + if( addNode != null ) + { + this.IncrementCurrentGenerationCount(); + } + } + + private void UpdateGenPosToIndexList() + { + if( m_startNode == null ) + return; + + //after the modification to have the item count stored "locally" in the DetailGeneratorNodes, + //it becomes important to have the nodes updated when the layout of the items changes. + foreach( var detailNode in this.GetDetailGeneratorNodes() ) + { + detailNode.UpdateItemCount(); + } + + var nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + var cachedDetailNode = default( DetailGeneratorNode ); + var cachedDetailNodeIndex = -1; + var previousDetailIndex = -1; + + //loop through the realized items. By design they are present sequentially in the linked list, so I do not need to reset the GeneratorNodeHelper + for( int i = 0; i < m_genPosToItem.Count; i++ ) + { + var item = m_genPosToItem[ i ]; + var node = m_genPosToNode[ i ]; + var detailNode = node as DetailGeneratorNode; + + int index; + + if( detailNode == null ) + { + if( !nodeHelper.FindNode( node ) ) + throw DataGridException.Create( "Realized item not found.", m_dataGridControl ); + + index = nodeHelper.FindItem( item ); + if( index < 0 ) + throw DataGridException.Create( "Realized item not found.", m_dataGridControl ); + + var itemsNode = nodeHelper.CurrentNode as ItemsGeneratorNode; + if( itemsNode != null ) + { + index = nodeHelper.Index + itemsNode.IndexOf( item ); + } + } + else + { + if( cachedDetailNode != detailNode ) + { + cachedDetailNodeIndex = this.FindGlobalIndexForDetailNode( detailNode ); + cachedDetailNode = detailNode; + previousDetailIndex = -1; + } + + var detailIndex = detailNode.DetailGenerator.IndexFromRealizedItem( item, previousDetailIndex + 1, out previousDetailIndex ); + if( detailIndex < 0 ) + throw DataGridException.Create( "Realized item not found at detail level.", m_dataGridControl ); + + index = cachedDetailNodeIndex + detailIndex; + } + + if( ( i > 0 ) && ( index <= m_genPosToIndex[ i - 1 ] ) ) + throw DataGridException.Create( "Realized item re-indexed at wrong location.", m_dataGridControl ); + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_UpdateGenPosToIndexList, DataGridTraceMessages.IndexUpdated, DataGridTraceArgs.Container( m_genPosToContainer[ i ] ), DataGridTraceArgs.Node( m_genPosToNode[ i ] ), DataGridTraceArgs.Item( m_genPosToItem[ i ] ), DataGridTraceArgs.GeneratorIndex( i ), DataGridTraceArgs.From( m_genPosToIndex[ i ] ), DataGridTraceArgs.To( index ) ); + + m_genPosToIndex[ i ] = index; + } } private int IndexFromRealizedItem( object referenceItem, int startIndex, out int foundIndex ) @@ -5627,7 +5827,7 @@ namespace Xceed.Wpf.DataGrid var parentItemIndex = nodeHelper.FindItem( parentItem ); if( parentItemIndex < 0 ) - throw new DataGridInternalException( "Master item index is out of bound.", m_dataGridControl ); + throw DataGridException.Create( "Master item index is out of bound.", m_dataGridControl ); return offset + detailIndex + parentItemIndex + 1; } @@ -5638,24 +5838,14 @@ namespace Xceed.Wpf.DataGrid private void StartGenerator( GeneratorPosition startPos, GeneratorDirection direction ) { if( this.Status == GeneratorStatus.GeneratingContainers ) - DataGridException.ThrowSystemException( "Cannot perform this operation while the generator is busy generating items.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "Cannot perform this operation while the generator is busy generating items.", m_dataGridControl ); - //set the GeneratorStatus to "Generating" m_generatorStatus = GeneratorStatus.GeneratingContainers; - - //Initialize the Direction m_generatorDirection = direction; - - //retrieve the Index for the GeneratorPosition retrieved m_generatorCurrentGlobalIndex = this.IndexFromGeneratorPosition( startPos ); - int itemCount = this.ItemCount; - if( ( m_generatorCurrentGlobalIndex < 0 ) || ( ( itemCount > 0 ) && ( m_generatorCurrentGlobalIndex >= itemCount ) ) ) - DataGridException.ThrowSystemException( "The specified start position is outside the range of the Generator content.", - typeof( ArgumentOutOfRangeException ), m_dataGridControl.Name, "startPos" ); - - if( itemCount == 0 ) + var itemCount = this.ItemCount; + if( ( m_generatorCurrentGlobalIndex < 0 ) || ( m_generatorCurrentGlobalIndex >= itemCount ) ) return; //and create a node helper that will assist us during the Generation process... @@ -5664,12 +5854,12 @@ namespace Xceed.Wpf.DataGrid //position the GeneratorNodeHelper to the appropriate node if( !m_generatorNodeHelper.FindNodeForIndex( m_generatorCurrentGlobalIndex ) ) //find index?!?! //there was a problem moving the Node helper... - throw new DataGridInternalException( "Unable to move to the required generator node by using the current index.", m_dataGridControl ); + throw DataGridException.Create( "Unable to move to the required generator node by using the current index.", m_dataGridControl ); //Calculate the offset m_generatorCurrentOffset = m_generatorCurrentGlobalIndex - m_generatorNodeHelper.Index; - ItemsGeneratorNode itemsNode = m_generatorNodeHelper.CurrentNode as ItemsGeneratorNode; + var itemsNode = m_generatorNodeHelper.CurrentNode as ItemsGeneratorNode; if( itemsNode != null ) { m_generatorCurrentDetail = itemsNode.GetDetailNodeForIndex( m_generatorCurrentOffset, out m_generatorCurrentOffset, out m_generatorCurrentDetailIndex, out m_generatorCurrentDetailNodeIndex ); @@ -5679,7 +5869,7 @@ namespace Xceed.Wpf.DataGrid { // No detail generator should be started already. if( m_generatorCurrentDetailDisposable != null ) - throw new DataGridInternalException( "The detail generator is already started.", m_dataGridControl ); + throw DataGridException.Create( "The detail generator is already started.", m_dataGridControl ); m_generatorCurrentDetailDisposable = ( ( IItemContainerGenerator )m_generatorCurrentDetail.DetailGenerator ).StartAt( m_generatorCurrentDetail.DetailGenerator.GeneratorPositionFromIndex( m_generatorCurrentDetailIndex ), direction, true ); } @@ -5688,7 +5878,7 @@ namespace Xceed.Wpf.DataGrid private void StopGenerator() { if( this.Status != GeneratorStatus.GeneratingContainers ) - throw new DataGridInternalException( "Cannot perform this operation while the generator is busy generating items.", m_dataGridControl ); + throw DataGridException.Create( "Cannot perform this operation while the generator is busy generating items.", m_dataGridControl ); m_generatorNodeHelper = null; m_generatorCurrentOffset = -1; @@ -5719,9 +5909,8 @@ namespace Xceed.Wpf.DataGrid private GeneratorPosition FindNextUnrealizedGeneratorPosition( GeneratorPosition position ) { - GeneratorPosition retval = position; - - int index = this.IndexFromGeneratorPosition( position ) + 1; + var retval = position; + var index = this.IndexFromGeneratorPosition( position ) + 1; while( index < this.ItemCount ) { @@ -5743,52 +5932,21 @@ namespace Xceed.Wpf.DataGrid private GeneratorPosition FindPreviousUnrealizedGeneratorPosition( GeneratorPosition position ) { - int index = this.IndexFromGeneratorPosition( position ) - 1; - + var index = this.IndexFromGeneratorPosition( position ) - 1; while( index >= 0 ) { if( !m_genPosToIndex.Contains( index ) ) - { break; - } index--; } - GeneratorPosition retval = this.GeneratorPositionFromIndex( index ); - - return retval; - } - - private void RemoveContainer( DependencyObject container, object dataItem ) - { - m_dataGridControl.ClearItemContainer( container, dataItem ); - - if( this.IsRecyclingEnabled ) - { - this.EnqueueContainer( container, dataItem ); - - var dataItemStore = container.ReadLocalValue( CustomItemContainerGenerator.DataItemPropertyProperty ) as DataItemDataProviderBase; - if( dataItemStore != null ) - { - dataItemStore.ClearDataItem(); - } - - if( GroupLevelIndicatorPane.GetGroupLevel( container ) == -1 ) - { - container.ClearValue( GroupLevelIndicatorPane.GroupLevelProperty ); - } - - if( container is HeaderFooterItem ) - { - container.ClearValue( DataGridControl.StatContextPropertyKey ); - } - } + return this.GeneratorPositionFromIndex( index ); } private DependencyObject CreateContainerForItem( object dataItem, GeneratorNode node ) { - DependencyObject container = null; + var container = default( DependencyObject ); if( node is HeadersFootersGeneratorNode ) { @@ -5821,11 +5979,11 @@ namespace Xceed.Wpf.DataGrid } else { - throw new DataGridInternalException( "Cannot create container for the GeneratorNode, as it is not of a valid type.", m_dataGridControl ); + throw DataGridException.Create( "Cannot create container for the GeneratorNode, as it is not of a valid type.", m_dataGridControl ); } if( container == null ) - throw new DataGridInternalException( "A container could not be created or recycled for the GeneratorNode.", m_dataGridControl ); + throw DataGridException.Create( "A container could not be created or recycled for the GeneratorNode.", m_dataGridControl ); var dataItemStore = container.ReadLocalValue( CustomItemContainerGenerator.DataItemPropertyProperty ) as DataItemDataProviderBase; if( dataItemStore != null ) @@ -5847,8 +6005,8 @@ namespace Xceed.Wpf.DataGrid private void SetStatContext( DependencyObject container, GeneratorNode node ) { - GroupGeneratorNode parentGroup = node.Parent as GroupGeneratorNode; - DataGridCollectionViewGroup collectionViewGroup = null; + var parentGroup = node.Parent as GroupGeneratorNode; + var collectionViewGroup = default( DataGridCollectionViewGroup ); if( parentGroup != null ) { @@ -5869,6 +6027,19 @@ namespace Xceed.Wpf.DataGrid } } + private void ClearStatContext( DependencyObject container ) + { + if( GroupLevelIndicatorPane.GetGroupLevel( container ) == -1 ) + { + container.ClearValue( GroupLevelIndicatorPane.GroupLevelProperty ); + } + + if( container is HeaderFooterItem ) + { + container.ClearValue( DataGridControl.StatContextPropertyKey ); + } + } + private bool IsItemItsOwnContainer( object dataItem ) { return m_dataGridControl.IsItemItsOwnContainer( dataItem ); @@ -5878,23 +6049,22 @@ namespace Xceed.Wpf.DataGrid { if( this.IsRecyclingEnabled ) { - DependencyObject recycledContainer = null; - recycledContainer = this.DequeueHeaderFooterContainer( dataItem ); + var recycledContainer = this.DequeueHeaderFooterContainer( dataItem ); if( recycledContainer != null ) return recycledContainer; } //If the container cannot be recycled, then create a new one. - object realDataItem = dataItem; + var realDataItem = dataItem; if( dataItem.GetType() == typeof( GroupHeaderFooterItem ) ) { realDataItem = ( ( GroupHeaderFooterItem )dataItem ).Template; } - DataTemplate template = realDataItem as DataTemplate; + var template = realDataItem as DataTemplate; if( template == null ) { - GroupHeaderFooterItemTemplate vwc = realDataItem as GroupHeaderFooterItemTemplate; + var vwc = realDataItem as GroupHeaderFooterItemTemplate; if( vwc != null ) { vwc.Seal(); @@ -5902,10 +6072,10 @@ namespace Xceed.Wpf.DataGrid } if( template == null ) - throw new DataGridInternalException( "No template found for the creation of a header or footer container.", m_dataGridControl ); + throw DataGridException.Create( "No template found for the creation of a header or footer container.", m_dataGridControl ); } - HeaderFooterItem newItem = new HeaderFooterItem(); + var newItem = new HeaderFooterItem(); BindingOperations.SetBinding( newItem, HeaderFooterItem.ContentProperty, m_headerFooterDataContextBinding ); newItem.ContentTemplate = template; @@ -5915,20 +6085,106 @@ namespace Xceed.Wpf.DataGrid private int FindInsertionPoint( int itemIndex ) { - int i = 0; + var count = m_genPosToIndex.Count; - int collectionCount = m_genPosToIndex.Count; - for( i = 0; i < collectionCount; i++ ) + for( var i = 0; i < count; i++ ) { //if the item is larger in index, then I want to insert before it! if( m_genPosToIndex[ i ] > itemIndex ) + return i; + } + + return count; + } + + private void RemapFloatingDetails() + { + if( m_floatingDetails.Count == 0 ) + return; + + if( this.IsDetailsRemapDeferred ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_RemapFloatingDetails, DataGridTraceMessages.CannotRemapDetails ); + return; + } + + Debug.Assert( m_startNode != null, "Generator structure should already be created." ); + + while( m_floatingDetails.Count > 0 ) + { + var closeDetail = true; //using this approach to have a default behavior or closing the details, if something inconsistent occur (see Debug Asserts). + var itemToCheck = m_floatingDetails[ 0 ]; + m_floatingDetails.RemoveAt( 0 ); + + var nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + if( nodeHelper.AbsoluteFindItem( itemToCheck ) ) { - break; + var itemsNode = nodeHelper.CurrentNode as ItemsGeneratorNode; + if( itemsNode != null ) + { + var insertionIndex = itemsNode.Items.IndexOf( itemToCheck ); + if( insertionIndex < 0 ) + { + this.TraceEvent( TraceEventType.Critical, DataGridTraceEventId.CustomItemContainerGenerator_RemapFloatingDetails, DataGridTraceMessages.ItemNotBelongingToNode, DataGridTraceArgs.Item( itemToCheck ), DataGridTraceArgs.Node( itemsNode ) ); + } + + if( itemsNode.Details == null ) + { + itemsNode.Details = new SortedDictionary>(); + } + + try + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_RemapFloatingDetails, DataGridTraceMessages.RemapDetailNodes, DataGridTraceArgs.Item( itemToCheck ) ); + + var oldItemCount = this.ItemCount; + + itemsNode.Details.Add( insertionIndex, new List( m_masterToDetails[ itemToCheck ] ) ); + + var addCount = 0; + foreach( var detailNode in m_masterToDetails[ itemToCheck ] ) + { + // Refresh the item count in case it changed while the detail was floating. + detailNode.UpdateItemCount(); + + addCount += detailNode.ItemCount; + } + itemsNode.AdjustItemCount( addCount ); + + this.IncrementCurrentGenerationCount(); + + // The ItemsChanged event should not be raised if the new items are hidden under a collapsed group, or else the master node's ItemCount will become unbalanced. + var newItemCount = this.ItemCount; + if( oldItemCount != newItemCount ) + { + //ensure that no add event is sent when the generator is currently processing a Reset. + if( !this.IsHandlingGlobalItemsReset ) + { + this.SendAddEvent( addCount ); + } + } + + closeDetail = false; + } + catch( Exception e ) + { + //both the "Add" and the " [] " could throw if the key is already present or if its not... + throw new DataGridInternalException( e.Message, e, m_dataGridControl ); + } + } + else + { + this.TraceEvent( TraceEventType.Warning, DataGridTraceEventId.CustomItemContainerGenerator_RemapFloatingDetails, DataGridTraceMessages.UnexpectedNode, DataGridTraceArgs.Node( nodeHelper.CurrentNode ) ); + } } + if( closeDetail ) + { + //The item was not located in the generator, then it's time to "close" the detail node/generator + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_RemapFloatingDetails, DataGridTraceMessages.CollapsingDetail, DataGridTraceArgs.Item( itemToCheck ) ); + this.CloseDetailsForItem( itemToCheck, null ); + } } - - return i; } private void QueueDetailItemForRemapping( object item ) @@ -5936,17 +6192,134 @@ namespace Xceed.Wpf.DataGrid if( item == null ) return; - if( ( !m_floatingDetails.Contains( item ) ) && ( m_masterToDetails.ContainsKey( item ) ) ) + if( !m_masterToDetails.ContainsKey( item ) || m_floatingDetails.Contains( item ) ) + return; + + m_floatingDetails.Add( item ); + + this.InvalidateNodeTree(); + } + + private void CloseDetails( DetailConfiguration detailConfiguration ) + { + var details = new KeyValuePair>[ m_masterToDetails.Count ]; + ( ( ICollection>> )m_masterToDetails ).CopyTo( details, 0 ); + + foreach( var detail in details ) + { + this.CloseDetailsForItem( detail.Key, detailConfiguration ); + } + } + + private int CloseDetailsForItem( object dataItem, DetailConfiguration detailConfiguration ) + { + if( m_generatorStatus == GeneratorStatus.GeneratingContainers ) + throw DataGridException.Create( "Cannot perform this operation while the generator is busy generating items", m_dataGridControl ); + + if( dataItem is EmptyDataItem ) + { + this.TraceEvent( TraceEventType.Error, DataGridTraceEventId.CustomItemContainerGenerator_CloseDetailsForItem, DataGridTraceMessages.CannotCollapseDetail, DataGridTraceArgs.Item( dataItem ) ); + return -1; + } + + if( ( dataItem == null ) || ( !m_masterToDetails.ContainsKey( dataItem ) ) ) + return -1; //the item is no longer present in the opened details list... or item is invalid (null) + + var nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + var globalItemIndex = nodeHelper.FindItem( dataItem ); + var dataItemFound = ( globalItemIndex >= 0 ); + //Note: this function will only return index for items directly contained in this generator ( no details ). + + ItemsGeneratorNode masterNode; + + if( dataItemFound ) + { + masterNode = nodeHelper.CurrentNode as ItemsGeneratorNode; + } + else + { + nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + masterNode = ( nodeHelper.Contains( dataItem ) ) ? nodeHelper.CurrentNode as ItemsGeneratorNode : null; + } + + List oldDetails; + if( !m_masterToDetails.TryGetValue( dataItem, out oldDetails ) ) + { + this.TraceEvent( TraceEventType.Critical, DataGridTraceEventId.CustomItemContainerGenerator_CloseDetailsForItem, DataGridTraceMessages.DetailNotFound, DataGridTraceArgs.Item( dataItem ) ); + throw DataGridException.Create( "Detail not found", m_dataGridControl ); + } + + var count = 0; + var containers = new List(); + + for( int i = oldDetails.Count - 1; i >= 0; i-- ) + { + var detailNode = oldDetails[ i ]; + + if( ( detailConfiguration == null ) || ( detailConfiguration == detailNode.DetailContext.SourceDetailConfiguration ) ) + { + count += detailNode.ItemCount; + + this.RemoveGeneratedItems( detailNode, containers ); + this.ClearDetailGeneratorNode( detailNode ); + + oldDetails.RemoveAt( i ); + } + } + + if( oldDetails.Count == 0 ) { - m_floatingDetails.Add( item ); + m_masterToDetails.Remove( dataItem ); + m_floatingDetails.Remove( dataItem ); } + + if( ( masterNode != null ) && ( masterNode.Details != null ) ) + { + var indexOfItem = masterNode.Items.IndexOf( dataItem ); + + if( !masterNode.Details.TryGetValue( indexOfItem, out oldDetails ) ) + { + this.TraceEvent( TraceEventType.Critical, DataGridTraceEventId.CustomItemContainerGenerator_CloseDetailsForItem, DataGridTraceMessages.DetailNotFound, DataGridTraceArgs.Item( dataItem ) ); + throw DataGridException.Create( "Detail not found .. 2", m_dataGridControl ); + } + + for( int i = oldDetails.Count - 1; i >= 0; i-- ) + { + var detailNode = oldDetails[ i ]; + + if( ( detailConfiguration == null ) || ( detailConfiguration == detailNode.DetailContext.SourceDetailConfiguration ) ) + { + oldDetails.RemoveAt( i ); + } + } + + if( oldDetails.Count == 0 ) + { + masterNode.Details.Remove( indexOfItem ); + } + + masterNode.AdjustItemCount( -count ); + + if( masterNode.Details.Count == 0 ) + { + masterNode.Details = null; + } + } + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_CloseDetailsForItem, DataGridTraceMessages.DetailCollapsed, DataGridTraceArgs.Item( dataItem ) ); + + if( dataItemFound ) + { + this.IncrementCurrentGenerationCount(); + this.SendRemoveEvent( count, containers ); + } + + return globalItemIndex; } private DetailGeneratorNode CreateDetailGeneratorNode( object dataItem, DataGridCollectionViewBase collectionView, DetailConfiguration detailConfiguration ) { var detailDataGridContext = new DataGridContext( m_dataGridContext, m_dataGridControl, dataItem, collectionView, detailConfiguration ); - detailDataGridContext.SetAssociatedAutomationPeer(); - var detailGenerator = CustomItemContainerGenerator.CreateGenerator( m_dataGridControl, collectionView, detailDataGridContext, this ); detailGenerator.SetGenPosToIndexUpdateInhibiter( this ); detailGenerator.IsRecyclingEnabled = this.IsRecyclingEnabled; @@ -5974,45 +6347,41 @@ namespace Xceed.Wpf.DataGrid private void ClearDetailGeneratorNode( DetailGeneratorNode detailNode ) { - using( m_log.BeginBlock( this, CustomItemContainerGenerator.FormatObjectId( "ClearDetailGeneratorNode - DN", detailNode ) ) ) - { - m_dataGridControl.SelectionChangerManager.Begin(); + m_dataGridControl.SelectionChangerManager.Begin(); - try - { - m_dataGridControl.SelectionChangerManager.UnselectAllItems( detailNode.DetailContext ); - m_dataGridControl.SelectionChangerManager.UnselectAllCells( detailNode.DetailContext ); - } - finally - { - m_dataGridControl.SelectionChangerManager.End( false, false, false ); - } + try + { + m_dataGridControl.SelectionChangerManager.UnselectAllItems( detailNode.DetailContext ); + m_dataGridControl.SelectionChangerManager.UnselectAllCells( detailNode.DetailContext ); + } + finally + { + m_dataGridControl.SelectionChangerManager.End( false, false ); + } - m_dataGridControl.SaveDataGridContextState( detailNode.DetailContext, true, int.MaxValue ); + m_dataGridControl.SaveDataGridContextState( detailNode.DetailContext, true, int.MaxValue ); - CustomItemContainerGenerator detailGenerator = detailNode.DetailGenerator; + var detailGenerator = detailNode.DetailGenerator; - detailNode.CleanGeneratorNode(); + detailNode.CleanGeneratorNode(); - DetailsChangedEventManager.RemoveListener( detailGenerator, this ); - detailGenerator.ItemsChanged -= new CustomGeneratorChangedEventHandler( this.HandleDetailGeneratorContentChanged ); - detailGenerator.ContainersRemoved -= new ContainersRemovedEventHandler( this.OnDetailContainersRemoved ); - detailGenerator.SetGenPosToIndexUpdateInhibiter( null ); - detailGenerator.UnregisterEvents(); - detailGenerator.ClearEvents(); - } + DetailsChangedEventManager.RemoveListener( detailGenerator, this ); + detailGenerator.ItemsChanged -= new CustomGeneratorChangedEventHandler( this.HandleDetailGeneratorContentChanged ); + detailGenerator.ContainersRemoved -= new ContainersRemovedEventHandler( this.OnDetailContainersRemoved ); + detailGenerator.SetGenPosToIndexUpdateInhibiter( null ); + detailGenerator.UnregisterEvents(); + detailGenerator.ClearEvents(); } private void RegisterEvents() { Debug.Assert( m_dataGridControl != null ); Debug.Assert( m_collectionView != null ); - Debug.Assert( ( m_dataGridContext != null ) && ( m_dataGridContext.DetailConfigurations != null ) ); + Debug.Assert( m_dataGridContext != null ); CollectionChangedEventManager.AddListener( m_collectionView, this ); GroupConfigurationSelectorChangedEventManager.AddListener( m_dataGridContext, this ); - CollectionChangedEventManager.AddListener( m_dataGridContext.DetailConfigurations, this ); - PropertyChangedEventManager.AddListener( m_collectionView, this, "Groups" ); + PropertyChangedEventManager.AddListener( m_collectionView, this, string.Empty ); // The top most generator must register to additional events. if( m_dataGridContext.SourceDetailConfiguration == null ) @@ -6020,6 +6389,9 @@ namespace Xceed.Wpf.DataGrid ItemsSourceChangeCompletedEventManager.AddListener( m_dataGridControl, this ); ViewChangedEventManager.AddListener( m_dataGridControl, this ); ThemeChangedEventManager.AddListener( m_dataGridControl, this ); + + m_recyclingPools.ContainersRemoved += new ContainersRemovedEventHandler( this.OnRecyclingPoolsContainersRemoved ); + m_recyclingPools.RecyclingCandidatesCleaned += new RecyclingCandidatesCleanedEventHandler( this.OnRecyclingCandidatesCleaned ); } } @@ -6032,7 +6404,7 @@ namespace Xceed.Wpf.DataGrid CollectionChangedEventManager.RemoveListener( m_collectionView, this ); GroupConfigurationSelectorChangedEventManager.RemoveListener( m_dataGridContext, this ); CollectionChangedEventManager.RemoveListener( m_dataGridContext.DetailConfigurations, this ); - PropertyChangedEventManager.RemoveListener( m_collectionView, this, "Groups" ); + PropertyChangedEventManager.RemoveListener( m_collectionView, this, string.Empty ); // The top most generator must unregister from additional events. if( m_dataGridContext.SourceDetailConfiguration == null ) @@ -6040,6 +6412,9 @@ namespace Xceed.Wpf.DataGrid ItemsSourceChangeCompletedEventManager.RemoveListener( m_dataGridControl, this ); ViewChangedEventManager.RemoveListener( m_dataGridControl, this ); ThemeChangedEventManager.RemoveListener( m_dataGridControl, this ); + + m_recyclingPools.ContainersRemoved -= new ContainersRemovedEventHandler( this.OnRecyclingPoolsContainersRemoved ); + m_recyclingPools.RecyclingCandidatesCleaned -= new RecyclingCandidatesCleanedEventHandler( this.OnRecyclingCandidatesCleaned ); } } @@ -6051,47 +6426,259 @@ namespace Xceed.Wpf.DataGrid this.PropertyChanged = null; } - private void HandleDetailGeneratorContentChanged( object sender, CustomGeneratorChangedEventArgs e ) + internal int CreateDetailsHelper( ItemsGeneratorNode masterNode, object dataItem ) + { + var dataGridCollectionViewBase = ( m_dataGridContext != null ) ? m_dataGridContext.ItemsSourceCollection as DataGridCollectionViewBase + : default( DataGridCollectionViewBase ); + + if( dataGridCollectionViewBase == null ) + { + this.TraceEvent( TraceEventType.Critical, DataGridTraceEventId.CustomItemContainerGenerator_CreateDetailsHelper, DataGridTraceMessages.DetailNotSupported, + DataGridTraceArgs.DataSource( dataGridCollectionViewBase ) ); + } + + var totalAddCount = 0; + var newDetails = default( List ); + var detailsAlreadyExist = m_floatingDetails.Contains( dataItem ); + + if( detailsAlreadyExist ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_CreateDetailsHelper, DataGridTraceMessages.RemapDetailNodes, + DataGridTraceArgs.Item( dataItem ) ); + + newDetails = new List( m_masterToDetails[ dataItem ] ); + m_floatingDetails.Remove( dataItem ); + } + + var detailConfigurations = m_dataGridContext.DetailConfigurations; + + //If the master item was not found in the list of details pending requeuing, then create a new set of detail nodes + if( newDetails == null ) + { + newDetails = new List( detailConfigurations.Count ); + + foreach( DetailConfiguration detailConfig in detailConfigurations ) + { + if( detailConfig.IsAutoCreated ) + { + var defaultDetailConfig = m_dataGridContext.DefaultDetailConfiguration; + if( defaultDetailConfig == null ) + { + defaultDetailConfig = m_dataGridContext.GetDefaultDetailConfigurationForContext(); + } + + if( defaultDetailConfig != null ) + { + //if the default headers footers shall be used, add then to the detail config ( internally, it ensures that it is added only once ). + if( defaultDetailConfig.UseDefaultHeadersFooters ) + { + defaultDetailConfig.AddDefaultHeadersFooters(); + detailConfig.AddDefaultHeadersFooters(); + } + } + else + { + //if the default headers footers shall be used, add then to the detail config ( internally, it ensures that it is added only once ). + if( detailConfig.UseDefaultHeadersFooters ) + { + detailConfig.AddDefaultHeadersFooters(); + } + } + } + else + { + //if the default headers footers shall be used, add then to the detail config ( internally, it ensures that it is added only once ). + if( detailConfig.UseDefaultHeadersFooters ) + { + detailConfig.AddDefaultHeadersFooters(); + } + } + + // If the DetailConfiguration is not meant to be visible, then skip next section (creation of detail) and continue looping on other detail configurations + if( !detailConfig.Visible ) + continue; + + var newDetailCollectionViewBase = default( DataGridCollectionViewBase ); + var detailDataSource = default( IEnumerable ); + + // If the data source returned by the detailDescription is null ( or if there was no detail description ), then create an empty data source for the detail data. + if( detailDataSource == null ) + { + detailDataSource = new object[] { }; + } + + newDetailCollectionViewBase = dataGridCollectionViewBase.CreateDetailDataGridCollectionViewBase( detailDataSource, null, dataGridCollectionViewBase ); + + Debug.Assert( newDetailCollectionViewBase != null ); + + using( detailConfig.ColumnManager.DeferUpdate( new ColumnHierarchyManager.UpdateOptions( TableView.GetFixedColumnCount( detailConfig ), true ) ) ) + { + if( detailConfig.AutoCreateForeignKeyConfigurations && !detailConfig.ForeignKeysUpdatedOnAutoCreate ) + { + // Ensure to update the foreign key related properties before expanding detail + ForeignKeyConfiguration.UpdateColumnsForeignKeyConfigurationsFromDataGridCollectionView( detailConfig.Columns, + newDetailCollectionViewBase.ItemProperties, + detailConfig.AutoCreateForeignKeyConfigurations ); + detailConfig.ForeignKeysUpdatedOnAutoCreate = true; + } + } + + var newDetailNode = this.CreateDetailGeneratorNode( dataItem, newDetailCollectionViewBase, detailConfig ); + newDetails.Add( newDetailNode ); + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_CreateDetailsHelper, DataGridTraceMessages.DetailNodeAdded, + DataGridTraceArgs.Node( newDetailNode ), DataGridTraceArgs.Item( dataItem ) ); + + totalAddCount += newDetailNode.ItemCount; + } + } + else // there was details for the master item in the list to be requeued + { + // count the items from the details. + foreach( var detailNode in newDetails ) + { + totalAddCount += detailNode.ItemCount; + } + } + + // Plug details in the master items node. + var indexOfItem = masterNode.Items.IndexOf( dataItem ); + var details = masterNode.Details; + + if( details == null ) + { + details = new SortedDictionary>(); + masterNode.Details = details; + } + + details.Add( indexOfItem, newDetails ); + + masterNode.AdjustItemCount( totalAddCount ); + + if( !detailsAlreadyExist ) + { + m_masterToDetails.Add( dataItem, new List( newDetails ) ); + + for( int i = 0; i < newDetails.Count; i++ ) + { + m_dataGridControl.RestoreDataGridContextState( newDetails[ i ].DetailContext ); + } + } + else + { + var detailsMapped = m_masterToDetails.ContainsKey( dataItem ); + Debug.Assert( detailsMapped, "Item not found on master level." ); + + if( !detailsMapped ) + { + this.TraceEvent( TraceEventType.Warning, DataGridTraceEventId.CustomItemContainerGenerator_CreateDetailsHelper, DataGridTraceMessages.RemapZombieDetail, + DataGridTraceArgs.Item( dataItem ) ); + } + } + + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_CreateDetailsHelper, DataGridTraceMessages.DetailExpanded, + DataGridTraceArgs.Item( dataItem ) ); + + return totalAddCount; + } + + private void CreateDetailsForItem( object dataItem ) { - m_log.Assert( this, !this.IsHandlingGlobalItemsResetLocally, "Generator is already processing a HandleGlobalItemReset or CleanupGenerator" ); + if( m_generatorStatus == GeneratorStatus.GeneratingContainers ) + throw DataGridException.Create( "Cannot perform this operation while the generator is busy generating items", m_dataGridControl ); - if( this.IsHandlingGlobalItemsResetLocally ) + if( ( dataItem == null ) || ( dataItem is EmptyDataItem ) ) + { + this.TraceEvent( TraceEventType.Error, DataGridTraceEventId.CustomItemContainerGenerator_CreateDetailsForItem, DataGridTraceMessages.CannotExpandDetail, DataGridTraceArgs.Item( dataItem ) ); return; + } - m_log.Assert( this, m_startNode != null, "m_startNode != null" ); + if( m_masterToDetails.ContainsKey( dataItem ) ) + { + //before throwing, verify if the item is not currently pending requeue + if( !m_floatingDetails.Contains( dataItem ) ) + throw DataGridException.Create( "An attempt was made to create details for an item whose details are already mapped.", m_dataGridControl ); + } - CustomItemContainerGenerator detailGenerator = sender as CustomItemContainerGenerator; + var nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + var dataItemFound = ( nodeHelper.FindItem( dataItem ) >= 0 ); - m_log.Assert( this, detailGenerator != null, "detailGenerator != null" ); + //means either that the item is not present in the Generator or that a parent group of the item is collapsed... + if( !dataItemFound ) + { + //make sure it is the later, else throw an exception. + nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + if( !nodeHelper.Contains( dataItem ) ) + throw DataGridException.Create( "An attempt was made to create details for an item that does not belong to the generator.", m_dataGridControl ); + } - object masterItem; - DetailGeneratorNode detailNode = this.FindDetailGeneratorNodeForGenerator( detailGenerator, out masterItem ); + var masterNode = nodeHelper.CurrentNode as ItemsGeneratorNode; + if( masterNode == null ) + throw DataGridException.Create( "An attempt was made to create details for an item that does not map to an item node.", m_dataGridControl ); - m_log.Assert( this, masterItem != null, "masterItem != null" ); - m_log.Assert( this, detailNode != null, "detailNode != null" ); + try + { + var count = this.CreateDetailsHelper( masterNode, dataItem ); - if( ( detailNode != null ) && ( masterItem != null ) ) + this.IncrementCurrentGenerationCount(); + + if( dataItemFound ) + { + this.SendAddEvent( count ); + } + } + catch( Exception e ) { - switch( e.Action ) + throw new DataGridException( e.Message, e, m_dataGridControl ); + } + } + + private void HandleDetailGeneratorContentChanged( object sender, CustomGeneratorChangedEventArgs e ) + { + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_OnDetailGeneratorContentChanged, DataGridTraceArgs.Node( sender ) ) ) + { + if( this.IsHandlingGlobalItemsResetLocally ) { - case NotifyCollectionChangedAction.Add: - this.HandleDetailAddition( masterItem, detailNode, e ); - break; + this.TraceEvent( TraceEventType.Warning, DataGridTraceEventId.CustomItemContainerGenerator_OnDetailGeneratorContentChanged, DataGridTraceMessages.CannotProcessOnReset ); + return; + } - case NotifyCollectionChangedAction.Move: - case NotifyCollectionChangedAction.Remove: - this.HandleDetailMoveRemove( masterItem, detailNode, e ); - break; + var detailGenerator = sender as CustomItemContainerGenerator; - case NotifyCollectionChangedAction.Replace: //CustomItemContainerGenreator never issues a Replace! - throw new DataGridInternalException( "CustomItemContainerGenerator never notifies a Replace action.", m_dataGridControl ); + Debug.Assert( detailGenerator != null ); + Debug.Assert( m_startNode != null ); - case NotifyCollectionChangedAction.Reset: - this.HandleDetailReset( masterItem, detailNode ); - break; + object masterItem; + var detailNode = this.FindDetailGeneratorNodeForGenerator( detailGenerator, out masterItem ); - default: - break; + Debug.Assert( masterItem != null ); + Debug.Assert( detailNode != null ); + + if( ( detailNode != null ) && ( masterItem != null ) ) + { + this.TraceEvent( TraceEventType.Verbose, DataGridTraceEventId.CustomItemContainerGenerator_OnDetailGeneratorContentChanged, DataGridTraceArgs.Action( e.Action ), DataGridTraceArgs.Node( detailNode ), DataGridTraceArgs.Item( masterItem ) ); + + switch( e.Action ) + { + case NotifyCollectionChangedAction.Add: + this.HandleDetailAddition( masterItem, detailNode, e ); + break; + + case NotifyCollectionChangedAction.Move: + case NotifyCollectionChangedAction.Remove: + this.HandleDetailMoveRemove( masterItem, detailNode, e ); + break; + + case NotifyCollectionChangedAction.Replace: //CustomItemContainerGenreator never issues a Replace! + throw DataGridException.Create( "CustomItemContainerGenerator never notifies a Replace action.", m_dataGridControl ); + + case NotifyCollectionChangedAction.Reset: + this.HandleDetailReset( masterItem, detailNode ); + break; + + default: + break; + } } } } @@ -6102,20 +6689,17 @@ namespace Xceed.Wpf.DataGrid return; var nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); - var masterIndex = nodeHelper.FindItem( masterItem ); // The master item has been found. - if( masterIndex != -1 ) + if( nodeHelper.FindItem( masterItem ) >= 0 ) { - int globalIndex = -1; - var convertedGeneratorPosition = this.ConvertDetailGeneratorPosition( e.Position, masterItem, detailNode, out globalIndex ); var masterNode = ( ItemsGeneratorNode )nodeHelper.CurrentNode; - masterNode.AdjustItemCount( e.ItemCount ); + masterNode.AdjustItemCount( e.Count ); detailNode.UpdateItemCount(); this.IncrementCurrentGenerationCount(); - this.SendAddEvent( convertedGeneratorPosition, masterIndex + 1 + e.Index, e.ItemCount ); + this.SendAddEvent( e.Count ); } // The master item could be located inside a collapsed group. else @@ -6123,12 +6707,11 @@ namespace Xceed.Wpf.DataGrid //in that case, I need to determine the appropriate masterNode another way nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); if( !nodeHelper.Contains( masterItem ) ) - DataGridException.ThrowSystemException( "An attempt was made to add a detail for an item that does not belong to the generator.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "An attempt was made to add a detail for an item that does not belong to the generator.", m_dataGridControl ); var masterNode = ( ItemsGeneratorNode )nodeHelper.CurrentNode; - masterNode.AdjustItemCount( e.ItemCount ); + masterNode.AdjustItemCount( e.Count ); detailNode.UpdateItemCount(); this.IncrementCurrentGenerationCount(); @@ -6141,26 +6724,22 @@ namespace Xceed.Wpf.DataGrid return; var nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); - var masterIndex = nodeHelper.FindItem( masterItem ); // The master item has been found. - if( masterIndex != -1 ) + if( nodeHelper.FindItem( masterItem ) >= 0 ) { - int globalIndex = -1; - var convertedGeneratorPosition = this.ConvertDetailGeneratorPosition( e.OldPosition, masterItem, detailNode, out globalIndex ); - - this.RemoveDetailContainers( convertedGeneratorPosition, e.ItemUICount ); + this.RemoveDetailContainers( e.Containers ); if( e.Action == NotifyCollectionChangedAction.Remove ) { var masterNode = ( ItemsGeneratorNode )nodeHelper.CurrentNode; - masterNode.AdjustItemCount( -e.ItemCount ); + masterNode.AdjustItemCount( -e.Count ); detailNode.UpdateItemCount(); } this.IncrementCurrentGenerationCount(); - this.SendRemoveEvent( convertedGeneratorPosition, globalIndex, e.ItemCount, e.ItemUICount, e.RemovedContainers ); + this.SendRemoveEvent( e.Count, e.Containers ); } // The master item could be located inside a collapsed group. else @@ -6168,14 +6747,13 @@ namespace Xceed.Wpf.DataGrid //in that case, I need to determine the appropriate masterNode another way nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); if( !nodeHelper.Contains( masterItem ) ) - DataGridException.ThrowSystemException( "An attempt was made to move or remove a detail for an item that does not belong to the generator.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); + throw DataGridException.Create( "An attempt was made to move or remove a detail for an item that does not belong to the generator.", m_dataGridControl ); if( e.Action == NotifyCollectionChangedAction.Remove ) { var masterNode = ( ItemsGeneratorNode )nodeHelper.CurrentNode; - masterNode.AdjustItemCount( -e.ItemCount ); + masterNode.AdjustItemCount( -e.Count ); detailNode.UpdateItemCount(); } @@ -6185,166 +6763,57 @@ namespace Xceed.Wpf.DataGrid private void HandleDetailReset( object masterItem, DetailGeneratorNode detailNode ) { - if( m_floatingDetails.Contains( masterItem ) ) - return; - - var nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); - var masterIndex = nodeHelper.FindItem( masterItem ); - var masterItemFound = ( masterIndex != -1 ); - - // The master item could be located inside a collapsed group. - if( !masterItemFound ) - { - nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); - if( !nodeHelper.Contains( masterItem ) ) - DataGridException.ThrowSystemException( "An attempt was made to reset a detail for an item that does not belong to the generator.", - typeof( InvalidOperationException ), m_dataGridControl.Name ); - } - - var masterNode = ( ItemsGeneratorNode )nodeHelper.CurrentNode; - - List detailsForMaster; - if( ( masterNode.Details == null ) || !masterNode.Details.TryGetValue( masterNode.Items.IndexOf( masterItem ), out detailsForMaster ) ) - throw new DataGridInternalException( "An attempt was made to reset a detail that does not belong to the generator.", m_dataGridControl ); - - //start index will be ignored later on if the masterIndex is -1!! - int startIndex = nodeHelper.Index + masterNode.IndexOf( masterItem ) + 1; //details start a master index + 1 - - //this is required to ensure that if the details that resets is not the first one, the index is calculated appropriatly. - foreach( DetailGeneratorNode node in detailsForMaster ) - { - if( node == detailNode ) - break; - - startIndex += node.ItemCount; - } - - var removePosition = new GeneratorPosition( -1, 1 ); - int removedCount = 0; - var removedContainers = new List(); - var oldDetailCount = detailNode.ItemCount; - var hasOldDetailItems = ( oldDetailCount > 0 ); - - if( hasOldDetailItems ) + using( this.TraceBlock( DataGridTraceEventId.CustomItemContainerGenerator_HandleDetailReset ) ) { - // The information about the removal is only required when the master item is not collapsed. - if( masterItemFound ) + if( m_floatingDetails.Contains( masterItem ) ) { - removePosition = this.GetSafeGeneratorPositionFromIndex( startIndex ); - removedCount = this.RemoveGeneratedItems( startIndex, startIndex + oldDetailCount - 1, removedContainers ); + this.TraceEvent( TraceEventType.Information, DataGridTraceEventId.CustomItemContainerGenerator_HandleDetailReset, DataGridTraceMessages.DetailIsFloating ); + return; } - masterNode.AdjustItemCount( -oldDetailCount ); - } - - detailNode.UpdateItemCount(); - - GeneratorPosition addPosition = new GeneratorPosition( -1, 1 ); - int newDetailCount = detailNode.ItemCount; - bool hasNewDetailItems = ( newDetailCount > 0 ); + var nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + var masterItemFound = ( nodeHelper.FindItem( masterItem ) >= 0 ); - if( hasNewDetailItems ) - { - // The information about the addition is only required when the master item is not collapsed. - if( masterItemFound ) + // The master item could be located inside a collapsed group. + if( !masterItemFound ) { - addPosition = this.GetSafeGeneratorPositionFromIndex( startIndex ); - } + nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); + if( !nodeHelper.Contains( masterItem ) ) + { + this.TraceEvent( TraceEventType.Critical, DataGridTraceEventId.CustomItemContainerGenerator_HandleDetailReset, DataGridTraceMessages.ItemNotBelongingToGenerator ); + throw DataGridException.Create( "An attempt was made to reset a detail for an item that does not belong to the generator.", m_dataGridControl ); + } - masterNode.AdjustItemCount( newDetailCount ); - } + this.TraceEvent( TraceEventType.Information, DataGridTraceEventId.CustomItemContainerGenerator_HandleDetailReset, DataGridTraceMessages.ItemNotFoundOrCollapsed ); + } - this.IncrementCurrentGenerationCount(); + var masterNode = ( ItemsGeneratorNode )nodeHelper.CurrentNode; + var oldDetailCount = detailNode.ItemCount; + var oldContainers = m_genPosToContainer.Where( ( c, i ) => m_genPosToNode[ i ] == detailNode ).ToList(); - // The events must be raised only when the master item is not collapsed. - if( masterItemFound ) - { - if( hasOldDetailItems && hasNewDetailItems ) - { - this.SendResetEvent(); - } - else if( hasOldDetailItems ) + using( detailNode.DetailGenerator.InhibitItemsChanged() ) { - this.SendRemoveEvent( removePosition, masterIndex + 1, oldDetailCount, removedCount, removedContainers ); - } - else if( hasNewDetailItems ) - { - this.SendAddEvent( addPosition, masterIndex + 1, newDetailCount ); + detailNode.UpdateItemCount(); } - } - } - - private void RemoveDetailContainers( GeneratorPosition convertedGeneratorPosition, int removeCount ) - { - int removeGenPosIndex = convertedGeneratorPosition.Index; - if( convertedGeneratorPosition.Offset > 0 ) - { - Debug.Assert( convertedGeneratorPosition.Offset == 1 ); - removeGenPosIndex++; - } - - for( int i = 0; i < removeCount; i++ ) - { - this.GenPosArraysRemoveAt( removeGenPosIndex ); - } - } - - private GeneratorPosition ConvertDetailGeneratorPosition( GeneratorPosition referencePosition, object masterItem, DetailGeneratorNode detailNode, out int globalIndex ) - { - //If the requested generator position map past at least one generated item from the detail generator, then the job is easy... - if( referencePosition.Index >= 0 ) - { - int generatorIndex = this.FindGeneratorIndexForNode( detailNode, referencePosition.Index ); - // Ensure to return the globalIndex as -1 - // if the generator index is not found for - // a DetailNode. This can occur if a Detail - // is filtered out via AutoFiltering. - globalIndex = ( generatorIndex > -1 ) ? m_genPosToIndex[ generatorIndex ] : -1; + var newDetailCount = detailNode.ItemCount; + var newContainers = detailNode.DetailGenerator.m_genPosToContainer; - return new GeneratorPosition( generatorIndex, referencePosition.Offset ); - } - else - { - //This means the GeneratorPosition returned by the DetailGenerator is "before" any generated item from the detail generator. - //I need more complex detection of the GeneratorPosition. - - // First - Get the Index of the MasterItem - int masterIndex = this.IndexFromItem( masterItem ); - - //Second - Get the DetailGenerator's Index for the DetailGenerator's GenPos - int detailGeneratorIndex = detailNode.DetailGenerator.IndexFromGeneratorPosition( referencePosition ); - - globalIndex = masterIndex + detailGeneratorIndex + 1; - - // Finally - Have the Master Generator compute the GeneratorPosition from the sum of both - return this.GeneratorPositionFromIndex( globalIndex ); - } - } + masterNode.AdjustItemCount( newDetailCount - oldDetailCount ); - private int FindGeneratorIndexForNode( DetailGeneratorNode referenceNode, int offset ) - { - int offsetCounter = -1; + var containersRemoved = new HashSet(); + var containersMoved = new HashSet(); - for( int i = 0; i < m_genPosToNode.Count; i++ ) - { - GeneratorNode node = m_genPosToNode[ i ]; - if( node == referenceNode ) - { - offsetCounter++; - if( offsetCounter == offset ) - return i; - } + CustomItemContainerGenerator.FindChanges( oldContainers, newContainers, null, containersRemoved, containersMoved ); + this.ApplyDetailChanges( detailNode, newContainers, containersRemoved, containersMoved ); } - - return -1; } private DetailGeneratorNode FindDetailGeneratorNodeForGenerator( CustomItemContainerGenerator detailGenerator, out object masterItem ) { - foreach( KeyValuePair> detailsForItem in m_masterToDetails ) + foreach( var detailsForItem in m_masterToDetails ) { - foreach( DetailGeneratorNode detailNode in detailsForItem.Value ) + foreach( var detailNode in detailsForItem.Value ) { if( detailNode.DetailGenerator == detailGenerator ) { @@ -6366,9 +6835,8 @@ namespace Xceed.Wpf.DataGrid private IDisposable InhibitParentGenPosToIndexUpdate() { if( m_genPosToIndexInhibiter != null ) - { return m_genPosToIndexInhibiter.InhibitGenPosToIndexUpdates(); - } + return null; } @@ -6376,10 +6844,9 @@ namespace Xceed.Wpf.DataGrid { //this function will find an item in the m_genPosToItem, but will filter out those that belongs to details. //This is to avoid the problem caused by Detail items that belongs also to a master. - int retval = -1; - - int runningIndex = 0; - int itemCount = m_genPosToItem.Count; + var retval = -1; + var runningIndex = 0; + var itemCount = m_genPosToItem.Count; while( runningIndex < itemCount ) { @@ -6390,7 +6857,7 @@ namespace Xceed.Wpf.DataGrid break; //check if the item belongs to a Detail or not. - DetailGeneratorNode detailNode = m_genPosToNode[ retval ] as DetailGeneratorNode; + var detailNode = m_genPosToNode[ retval ] as DetailGeneratorNode; if( detailNode == null ) break; //the item is not a detail and therefore qualifies as a return value. @@ -6401,108 +6868,111 @@ namespace Xceed.Wpf.DataGrid return retval; } - private void EnqueueContainer( DependencyObject container, object item ) + private bool EnqueueContainer( DependencyObject container, object item ) { - RecyclingManager manager = m_dataGridContext.RecyclingManager; - - m_log.Assert( this, manager != null, "manager != null" ); - if( container is HeaderFooterItem ) { if( item is GroupHeaderFooterItem ) { - //If the group is not in the CollectionView anymore (e.g. all its rows have been deleted), do not recycle it. - CollectionViewGroup viewGroup = ( ( GroupHeaderFooterItem )item ).Group; - if( viewGroup == null ) - return; - - //The tree is already correctly created since we are recycling containers! - Group group; + //If the group does not exist anymore (i.e. all its rows have been deleted), do not recycle it. + var groupHeaderFooterItem = ( GroupHeaderFooterItem )item; + var collectionViewGroup = groupHeaderFooterItem.Group; + if( collectionViewGroup == null ) + return false; - using( this.SetIsEnsuringNodeTreeCreated() ) + string groupBy = null; + if( collectionViewGroup is DataGridCollectionViewGroup ) { - group = this.GetGroupFromCollectionViewGroup( viewGroup ); + groupBy = ( ( DataGridCollectionViewGroup )collectionViewGroup ).GroupByName; } - if( group == null ) - return; - - string groupBy = group.GroupBy; if( string.IsNullOrEmpty( groupBy ) ) - return; + { + var group = this.GetGroupFromCollectionViewGroupCore( collectionViewGroup ); + if( group == null ) + return false; + + groupBy = group.GroupBy; + if( string.IsNullOrEmpty( groupBy ) ) + return false; + } - manager.EnqueueGroupHeaderFooterContainer( groupBy, item, container ); + m_recyclingPools.GetGroupHeaderFooterItemContainerPool( m_dataGridContext.SourceDetailConfiguration, true ).Enqueue( groupBy, groupHeaderFooterItem.Template, container ); } else { - manager.EnqueueHeaderFooterContainer( item, container ); + m_recyclingPools.GetHeaderFooterItemContainerPool( m_dataGridContext.SourceDetailConfiguration, true ).Enqueue( item, container ); } } else { - manager.EnqueueItemContainer( item, container ); + m_recyclingPools.GetItemContainerPool( m_dataGridContext.SourceDetailConfiguration, true ).Enqueue( item, container ); } + + return true; } private DependencyObject DequeueItemContainer( object item ) { - RecyclingManager manager = m_dataGridContext.RecyclingManager; - - m_log.Assert( this, manager != null, "manager != null" ); + var pool = m_recyclingPools.GetItemContainerPool( m_dataGridContext.SourceDetailConfiguration ); + if( pool == null ) + return null; - return manager.DequeueItemContainer( item ); + return pool.Dequeue( item ); } private DependencyObject DequeueHeaderFooterContainer( object item ) { - RecyclingManager manager = m_dataGridContext.RecyclingManager; - - m_log.Assert( this, manager != null, "manager != null" ); + if( !( item is GroupHeaderFooterItem ) ) + { + var pool = m_recyclingPools.GetHeaderFooterItemContainerPool( m_dataGridContext.SourceDetailConfiguration ); + if( pool == null ) + return null; - if( item is GroupHeaderFooterItem ) + return pool.Dequeue( item ); + } + else { - CollectionViewGroup viewGroup = ( ( GroupHeaderFooterItem )item ).Group; - if( viewGroup == null ) + var pool = m_recyclingPools.GetGroupHeaderFooterItemContainerPool( m_dataGridContext.SourceDetailConfiguration ); + if( pool == null ) return null; - //The tree is already correctly created since we are recycling containers! - Group group; + var groupHeaderFooterItem = ( GroupHeaderFooterItem )item; + var collectionViewGroup = groupHeaderFooterItem.Group; + if( collectionViewGroup == null ) + return null; - using( this.SetIsEnsuringNodeTreeCreated() ) + string groupBy = null; + if( collectionViewGroup is DataGridCollectionViewGroup ) { - group = this.GetGroupFromCollectionViewGroup( viewGroup ); + groupBy = ( ( DataGridCollectionViewGroup )collectionViewGroup ).GroupByName; } - if( group == null ) - return null; - - string groupBy = group.GroupBy; if( string.IsNullOrEmpty( groupBy ) ) - return null; + { + var group = this.GetGroupFromCollectionViewGroupCore( collectionViewGroup ); + if( group == null ) + return null; - return manager.DequeueGroupHeaderFooterContainer( groupBy, item ); - } - else - { - return manager.DequeueHeaderFooterContainer( item ); + groupBy = group.GroupBy; + if( string.IsNullOrEmpty( groupBy ) ) + return null; + } + + return pool.Dequeue( groupBy, groupHeaderFooterItem.Template ); } } - private void OnDetailContainersRemoved( object sender, ContainersRemovedEventArgs e ) + internal void CleanRecyclingCandidates() { - if( m_containersRemovedDeferCount > 0 ) - { - m_deferredContainersRemoved.AddRange( e.RemovedContainers ); - } - else - { - this.NotifyContainersRemoved( e ); - } + m_recyclingPools.CleanRecyclingCandidates(); } - private IDisposable DeferContainersRemovedNotification() + private void OnDetailContainersRemoved( object sender, ContainersRemovedEventArgs e ) { - return new DeferContainersRemovedDisposable( this ); + Debug.Assert( !this.IsRecyclingEnabled ); + + this.OnContainersRemoved( e.RemovedContainers ); } private DependencyObject CreateNextItemContainer( object item ) @@ -6557,6 +7027,82 @@ namespace Xceed.Wpf.DataGrid return collectionView.SourceCollection as IList; } + private static void FindChanges( + IList source, + IList destination, + ICollection itemsAdded, + ICollection itemsRemoved, + ICollection itemsMoved ) + { + if( source == null ) + throw new ArgumentNullException( "source" ); + + if( destination == null ) + throw new ArgumentNullException( "destination" ); + + // There is nothing to do since the caller is not interested by the result. + if( ( itemsAdded == null ) && ( itemsRemoved == null ) && ( itemsMoved == null ) ) + return; + + var sourceCount = source.Count; + var sourcePositions = new Dictionary( sourceCount ); + var sequence = new List( Math.Min( sourceCount, destination.Count ) ); + var isAlive = new BitArray( sourceCount, false ); + var hasNotMoved = default( BitArray ); + + for( var i = 0; i < sourceCount; i++ ) + { + sourcePositions.Add( source[ i ], i ); + } + + foreach( var item in destination ) + { + int index; + + if( sourcePositions.TryGetValue( item, out index ) ) + { + isAlive[ index ] = true; + sequence.Add( index ); + } + else if( itemsAdded != null ) + { + itemsAdded.Add( item ); + } + } + + // We may omit this part of the algorithm if the caller is not interested by the items that have moved. + if( itemsMoved != null ) + { + hasNotMoved = new BitArray( sourceCount, false ); + + // The subsequence contains the position of the item that are in the destination collection and that have not moved. + foreach( var index in LongestIncreasingSubsequence.Find( sequence ) ) + { + hasNotMoved[ index ] = true; + } + } + + // We may omit this part of the algorithm if the caller is not interested by the items that have moved or were removed. + if( ( itemsRemoved != null ) || ( itemsMoved != null ) ) + { + for( var i = 0; i < sourceCount; i++ ) + { + if( isAlive[ i ] ) + { + // We check if the move collection is not null first because the bit array is null when the move collection is null. + if( ( itemsMoved != null ) && !hasNotMoved[ i ] ) + { + itemsMoved.Add( source[ i ] ); + } + } + else if( itemsRemoved != null ) + { + itemsRemoved.Add( source[ i ] ); + } + } + } + } + public void Skip() { if( m_generatorDirection == GeneratorDirection.Forward ) @@ -6569,8 +7115,6 @@ namespace Xceed.Wpf.DataGrid } } - // Data Members - #region Private Fields private BitVector32 m_flags = new BitVector32(); @@ -6593,6 +7137,8 @@ namespace Xceed.Wpf.DataGrid private readonly DataGridContext m_dataGridContext; private readonly CollectionView m_collectionView; + private readonly CustomItemContainerGeneratorRecyclingPools m_recyclingPools; + private int m_lastValidItemCountGeneration = 0; private int m_cachedItemCount = 0; @@ -6615,9 +7161,6 @@ namespace Xceed.Wpf.DataGrid private IInhibitGenPosToIndexUpdating m_genPosToIndexInhibiter; // = null private IDisposable m_currentGenPosToIndexInhibiterDisposable; // = null - private List m_deferredContainersRemoved = new List(); - private int m_containersRemovedDeferCount = 0; - private Binding m_headerFooterDataContextBinding; #endregion @@ -6625,47 +7168,46 @@ namespace Xceed.Wpf.DataGrid #region IWeakEventListener Members bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) + { + return this.OnReceiveWeakEvent( managerType, sender, e ); + } + + protected virtual bool OnReceiveWeakEvent( Type managerType, object sender, EventArgs e ) { if( managerType == typeof( CollectionChangedEventManager ) ) { - var nccArgs = ( NotifyCollectionChangedEventArgs )e; + var eventArgs = ( ( NotifyCollectionChangedEventArgs )e ).GetRangeActionOrSelf(); if( sender == m_collectionView ) { - this.OnItemsChanged( sender, nccArgs.GetRangeActionOrSelf() ); - return true; + this.OnItemsChanged( sender, eventArgs ); } else if( sender == m_groupsCollection ) { - this.OnGroupsChanged( sender, nccArgs ); - return true; + this.OnGroupsChanged( sender, eventArgs ); } else if( sender == m_dataGridContext.DetailConfigurations ) { - this.OnDetailConfigurationsChanged( sender, nccArgs ); - return true; + this.OnDetailConfigurationsChanged( sender, eventArgs ); } } else if( managerType == typeof( PropertyChangedEventManager ) ) { - var pcArgs = ( PropertyChangedEventArgs )e; + var eventArgs = ( PropertyChangedEventArgs )e; if( sender == m_collectionView ) { - this.OnCollectionViewGroupsPropertyChanged(); - return true; + this.OnCollectionViewPropertyChanged( eventArgs ); } else { //this is only registered on the DataGridContext, this has the effect of forwarding property changes for all properties of the DataGridContext - this.OnNotifyPropertyChanged( pcArgs ); - return true; + this.OnNotifyPropertyChanged( eventArgs ); } } else if( ( managerType == typeof( ViewChangedEventManager ) ) || ( managerType == typeof( ThemeChangedEventManager ) ) ) { this.OnViewThemeChanged( sender, e ); - return true; } else if( managerType == typeof( DetailsChangedEventManager ) ) { @@ -6673,21 +7215,21 @@ namespace Xceed.Wpf.DataGrid { this.DetailsChanged( sender, e ); } - - return true; } else if( managerType == typeof( ItemsSourceChangeCompletedEventManager ) ) { this.OnItemsSourceChanged( sender, e ); - return true; } else if( managerType == typeof( GroupConfigurationSelectorChangedEventManager ) ) { this.OnGroupConfigurationSelectorChanged(); - return true; + } + else + { + return false; } - return false; + return true; } #endregion @@ -6698,10 +7240,11 @@ namespace Xceed.Wpf.DataGrid private void OnNotifyPropertyChanged( PropertyChangedEventArgs e ) { - if( this.PropertyChanged != null ) - { - this.PropertyChanged( this, e ); - } + var handler = this.PropertyChanged; + if( handler == null ) + return; + + handler.Invoke( this, e ); } #endregion @@ -6832,7 +7375,14 @@ namespace Xceed.Wpf.DataGrid { get { - return m_flag.IsSet; + if( m_flag.IsSet ) + return true; + + var parent = this.GetFlag( m_index - 1 ); + if( parent != null ) + return parent.IsSet; + + return false; } } @@ -6843,17 +7393,23 @@ namespace Xceed.Wpf.DataGrid internal LeveledAutoResetFlag GetChild() { - int index = m_index + 1; - if( index < m_levels.Count ) - { - var flag = ( LeveledAutoResetFlag )m_levels[ index ].Target; - if( flag != null ) - return flag; - } + var index = m_index + 1; + var flag = this.GetFlag( index ); + + if( flag != null ) + return flag; return new LeveledAutoResetFlag( m_levels, index ); } + private LeveledAutoResetFlag GetFlag( int index ) + { + if( ( index < 0 ) || ( index >= m_levels.Count ) ) + return null; + + return ( LeveledAutoResetFlag )m_levels[ index ].Target; + } + private readonly IList m_levels; private readonly AutoResetFlag m_flag; private readonly int m_index; @@ -6861,6 +7417,48 @@ namespace Xceed.Wpf.DataGrid #endregion + #region BubbleDirtyFlag Private Class + + private sealed class BubbleDirtyFlag + { + internal BubbleDirtyFlag( bool isSet ) + : this( null, isSet ) + { + } + + internal BubbleDirtyFlag( BubbleDirtyFlag parent, bool isSet ) + { + m_parent = parent; + + this.IsSet = isSet; + } + + internal bool IsSet + { + get + { + return m_isSet; + } + set + { + if( value == m_isSet ) + return; + + m_isSet = value; + + if( value && ( m_parent != null ) ) + { + m_parent.IsSet = true; + } + } + } + + private readonly BubbleDirtyFlag m_parent; + private bool m_isSet; + } + + #endregion + #region CustomItemContainerGeneratorDisposableDisposer Private Class private sealed class CustomItemContainerGeneratorDisposableDisposer : IDisposable @@ -6900,10 +7498,9 @@ namespace Xceed.Wpf.DataGrid private void Dispose( bool disposing ) { - var generator = m_generator; - // Prevent this method from being called more than once. - if( Interlocked.CompareExchange( ref m_generator, null, generator ) == null ) + var generator = Interlocked.Exchange( ref m_generator, null ); + if( generator == null ) return; generator.StopGenerator(); @@ -6923,14 +7520,14 @@ namespace Xceed.Wpf.DataGrid private sealed class GenPosToIndexInhibitionDisposable : IDisposable { - public GenPosToIndexInhibitionDisposable( CustomItemContainerGenerator generator ) + internal GenPosToIndexInhibitionDisposable( CustomItemContainerGenerator generator ) { if( generator == null ) throw new ArgumentNullException( "generator" ); m_generator = generator; - m_generator.m_genPosToIndexUpdateInhibitCount++; + Interlocked.Increment( ref m_generator.m_genPosToIndexUpdateInhibitCount ); if( m_generator.m_genPosToIndexInhibiter != null ) { @@ -6938,15 +7535,18 @@ namespace Xceed.Wpf.DataGrid } } - #region IDisposable Members - - public void Dispose() + private void Dispose( bool disposing ) { - m_generator.m_genPosToIndexUpdateInhibitCount--; + var generator = Interlocked.Exchange( ref m_generator, null ); + if( generator == null ) + return; - if( ( m_generator.m_genPosToIndexUpdateInhibitCount == 0 ) && ( m_generator.GenPosToIndexNeedsUpdate ) ) + if( Interlocked.Decrement( ref generator.m_genPosToIndexUpdateInhibitCount ) == 0 ) { - m_generator.IncrementCurrentGenerationCount(); + if( generator.GenPosToIndexNeedsUpdate ) + { + generator.IncrementCurrentGenerationCount(); + } } if( m_nestedDisposable != null ) @@ -6956,46 +7556,19 @@ namespace Xceed.Wpf.DataGrid } } - #endregion - - private CustomItemContainerGenerator m_generator; // = null - private IDisposable m_nestedDisposable; // = null - } - - #endregion - - #region DeferContainersRemovedDisposable Private Class - - private sealed class DeferContainersRemovedDisposable : IDisposable - { - public DeferContainersRemovedDisposable( CustomItemContainerGenerator generator ) + void IDisposable.Dispose() { - if( generator == null ) - throw new ArgumentNullException( "generator" ); - - m_generator = generator; - - m_generator.m_log.Assert( this, ( m_generator.m_containersRemovedDeferCount != 0 ) || ( m_generator.m_deferredContainersRemoved.Count == 0 ), "( m_generator.m_containersRemovedDeferCount != 0 ) || ( m_generator.m_deferredContainersRemoved.Count == 0 )" ); - - m_generator.m_containersRemovedDeferCount++; + this.Dispose( true ); + GC.SuppressFinalize( this ); } - #region IDisposable Members - - public void Dispose() + ~GenPosToIndexInhibitionDisposable() { - m_generator.m_containersRemovedDeferCount--; - - if( ( m_generator.m_containersRemovedDeferCount == 0 ) && ( m_generator.m_deferredContainersRemoved.Count > 0 ) ) - { - m_generator.NotifyContainersRemoved( new ContainersRemovedEventArgs( m_generator.m_deferredContainersRemoved ) ); - m_generator.m_deferredContainersRemoved.Clear(); - } + this.Dispose( false ); } - #endregion - private CustomItemContainerGenerator m_generator; // = null + private IDisposable m_nestedDisposable; // = null } #endregion @@ -7005,9 +7578,10 @@ namespace Xceed.Wpf.DataGrid [Flags] private enum CustomItemContainerGeneratorFlags { - RecyclingEnabled = 1, - InUse = 2, - GenPosToIndexNeedsUpdate = 4, + RecyclingEnabled = 1 << 0, + InUse = 1 << 1, + GenPosToIndexNeedsUpdate = 1 << 2, + ForceReset = 1 << 3, } #endregion diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/CustomItemContainerGeneratorRecyclingPools.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/CustomItemContainerGeneratorRecyclingPools.cs new file mode 100644 index 00000000..79678e3d --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/CustomItemContainerGeneratorRecyclingPools.cs @@ -0,0 +1,306 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Windows; +using Xceed.Utils.Wpf; + +namespace Xceed.Wpf.DataGrid +{ + internal sealed class CustomItemContainerGeneratorRecyclingPools + { + #region ContainersRemoved Event + + internal event ContainersRemovedEventHandler ContainersRemoved; + + private void OnContainersRemoved() + { + if( ( m_containersRemoved == null ) || ( m_deferCount != 0 ) ) + return; + + var containers = m_containersRemoved; + m_containersRemoved = null; + + if( containers.Count <= 0 ) + return; + + var handler = this.ContainersRemoved; + if( handler == null ) + return; + + handler.Invoke( this, new ContainersRemovedEventArgs( containers ) ); + } + + #endregion + + #region RecyclingCandidateCleaned Event + + internal event RecyclingCandidatesCleanedEventHandler RecyclingCandidatesCleaned; + + private void OnRecyclingCandidatesCleaned( List recyclingCandidates ) + { + if( recyclingCandidates.Count == 0 ) + return; + + var handler = this.RecyclingCandidatesCleaned; + if( handler == null ) + return; + + handler.Invoke( this, new RecyclingCandidatesCleanedEventArgs( recyclingCandidates ) ); + } + + #endregion + + internal IDisposable DeferContainersRemoved() + { + return new DeferredDisposable( new DeferContainersRemovedState( this ) ); + } + + internal void Clear() + { + m_containersRemoved = m_containersRemoved ?? new List(); + + this.ClearPools( m_itemContainerPools, m_containersRemoved, pool => pool.Clear() ); + this.ClearPools( m_headerFooterItemContainerPools, m_containersRemoved, pool => pool.Clear() ); + this.ClearPools( m_groupHeaderFooterItemContainerPools, m_containersRemoved, pool => pool.Clear() ); + + this.OnContainersRemoved(); + } + + internal void Clear( DetailConfiguration detailConfiguration ) + { + m_containersRemoved = m_containersRemoved ?? new List(); + + var key = CustomItemContainerGeneratorRecyclingPools.GetKey( detailConfiguration ); + + var itemContainerPool = default( ItemContainerRecyclingPool ); + if( m_itemContainerPools.TryGetValue( key, out itemContainerPool ) ) + { + m_itemContainerPools.Remove( key ); + + this.ClearPool( itemContainerPool, m_containersRemoved, pool => pool.Clear() ); + } + + var headerFooterItemContainerPool = default( HeaderFooterItemContainerRecyclingPool ); + if( m_headerFooterItemContainerPools.TryGetValue( key, out headerFooterItemContainerPool ) ) + { + m_headerFooterItemContainerPools.Remove( key ); + + this.ClearPool( headerFooterItemContainerPool, m_containersRemoved, pool => pool.Clear() ); + } + + var groupHeaderFooterItemContainerPool = default( GroupHeaderFooterItemContainerRecyclingPool ); + if( m_groupHeaderFooterItemContainerPools.TryGetValue( key, out groupHeaderFooterItemContainerPool ) ) + { + m_groupHeaderFooterItemContainerPools.Remove( key ); + + this.ClearPool( groupHeaderFooterItemContainerPool, m_containersRemoved, pool => pool.Clear() ); + } + + this.OnContainersRemoved(); + } + + internal void CleanRecyclingCandidates() + { + var recyclingCandidates = new List( 4 ); + + foreach( var pool in m_itemContainerPools.Values ) + { + foreach( var container in pool ) + { + var dataGridItemContainer = container as IDataGridItemContainer; + if( dataGridItemContainer != null && dataGridItemContainer.IsRecyclingCandidate ) + { + dataGridItemContainer.IsRecyclingCandidate = false; + dataGridItemContainer.CleanRecyclingCandidate(); + recyclingCandidates.Add( container ); + } + } + } + + foreach( var pool in m_headerFooterItemContainerPools.Values ) + { + foreach( var container in pool ) + { + var dataGridItemContainer = container as IDataGridItemContainer; + if( dataGridItemContainer != null && dataGridItemContainer.IsRecyclingCandidate ) + { + dataGridItemContainer.IsRecyclingCandidate = false; + dataGridItemContainer.CleanRecyclingCandidate(); + recyclingCandidates.Add( container ); + } + } + } + + foreach( var pool in m_groupHeaderFooterItemContainerPools.Values ) + { + foreach( var container in pool ) + { + var dataGridItemContainer = container as IDataGridItemContainer; + if( dataGridItemContainer != null && dataGridItemContainer.IsRecyclingCandidate ) + { + dataGridItemContainer.IsRecyclingCandidate = false; + dataGridItemContainer.CleanRecyclingCandidate(); + recyclingCandidates.Add( container ); + } + } + } + + this.OnRecyclingCandidatesCleaned( recyclingCandidates ); + } + + internal ItemContainerRecyclingPool GetItemContainerPool( DetailConfiguration detailConfiguration ) + { + return this.GetPool( m_itemContainerPools, detailConfiguration, false ); + } + + internal ItemContainerRecyclingPool GetItemContainerPool( DetailConfiguration detailConfiguration, bool create ) + { + return this.GetPool( m_itemContainerPools, detailConfiguration, create ); + } + + internal HeaderFooterItemContainerRecyclingPool GetHeaderFooterItemContainerPool( DetailConfiguration detailConfiguration ) + { + return this.GetPool( m_headerFooterItemContainerPools, detailConfiguration, false ); + } + + internal HeaderFooterItemContainerRecyclingPool GetHeaderFooterItemContainerPool( DetailConfiguration detailConfiguration, bool create ) + { + return this.GetPool( m_headerFooterItemContainerPools, detailConfiguration, create ); + } + + internal GroupHeaderFooterItemContainerRecyclingPool GetGroupHeaderFooterItemContainerPool( DetailConfiguration detailConfiguration ) + { + return this.GetPool( m_groupHeaderFooterItemContainerPools, detailConfiguration, false ); + } + + internal GroupHeaderFooterItemContainerRecyclingPool GetGroupHeaderFooterItemContainerPool( DetailConfiguration detailConfiguration, bool create ) + { + return this.GetPool( m_groupHeaderFooterItemContainerPools, detailConfiguration, create ); + } + + private T GetPool( Dictionary pools, DetailConfiguration detailConfiguration, bool create ) where T : class, new() + { + if( pools == null ) + throw new ArgumentNullException( "pools" ); + + var key = CustomItemContainerGeneratorRecyclingPools.GetKey( detailConfiguration ); + var pool = default( T ); + + if( !pools.TryGetValue( key, out pool ) ) + { + if( create ) + { + pool = new T(); + pools.Add( key, pool ); + } + else + { + pool = null; + } + } + + return pool; + } + + private void ClearPools( + Dictionary pools, + ICollection containers, + Action clearPool ) where T : IEnumerable + { + Debug.Assert( pools != null ); + + foreach( var pool in pools.Values ) + { + this.ClearPool( pool, containers, clearPool ); + } + + pools.Clear(); + } + + private void ClearPool( + T pool, + ICollection containers, + Action clearPool ) where T : IEnumerable + { + Debug.Assert( pool != null ); + Debug.Assert( clearPool != null ); + + foreach( var container in pool ) + { + containers.Add( container ); + } + + clearPool.Invoke( pool ); + } + + private static object GetKey( DetailConfiguration detailConfiguration ) + { + return detailConfiguration ?? CustomItemContainerGeneratorRecyclingPools.MasterConfiguration; + } + + private static readonly object MasterConfiguration = new object(); + + private int m_deferCount; //0 + private List m_containersRemoved; //null + + private readonly Dictionary m_itemContainerPools = new Dictionary(); + private readonly Dictionary m_headerFooterItemContainerPools = new Dictionary(); + private readonly Dictionary m_groupHeaderFooterItemContainerPools = new Dictionary(); + + #region DeferContainersRemovedState Private Class + + private sealed class DeferContainersRemovedState : DeferredDisposableState + { + internal DeferContainersRemovedState( CustomItemContainerGeneratorRecyclingPools target ) + { + if( target == null ) + throw new ArgumentNullException( "target" ); + + m_target = target; + } + + protected override bool IsDeferred + { + get + { + return ( m_target.m_deferCount != 0 ); + } + } + + protected override void Increment() + { + m_target.m_deferCount++; + } + + protected override void Decrement() + { + m_target.m_deferCount--; + } + + protected override void OnDeferEnded( bool disposing ) + { + m_target.OnContainersRemoved(); + } + + private readonly CustomItemContainerGeneratorRecyclingPools m_target; + } + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/DataItemDataProviderBase.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/DataItemDataProviderBase.cs index 18b5a77f..83187b67 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/DataItemDataProviderBase.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/DataItemDataProviderBase.cs @@ -15,11 +15,14 @@ ***********************************************************************************/ using System.Windows.Data; +using Xceed.Wpf.DataGrid.Utils; namespace Xceed.Wpf.DataGrid { internal abstract class DataItemDataProviderBase : DataSourceProvider { + internal static readonly string DataPropertyName = PropertyHelper.GetPropertyName( ( DataItemDataProviderBase s ) => s.Data ); + #region IsEmpty Property public abstract bool IsEmpty diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/DetailGeneratorNode.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/DetailGeneratorNode.cs index 41bdea0e..e2e791fa 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/DetailGeneratorNode.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/DetailGeneratorNode.cs @@ -15,24 +15,22 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Text; namespace Xceed.Wpf.DataGrid { internal partial class DetailGeneratorNode : GeneratorNode { - public DetailGeneratorNode( DataGridContext context, CustomItemContainerGenerator generator ) + internal DetailGeneratorNode( DataGridContext dataGridContext, CustomItemContainerGenerator generator ) : base( null ) { + if( dataGridContext == null ) + throw new ArgumentNullException( "dataGridContext" ); + if( generator == null ) throw new ArgumentNullException( "generator" ); - if( context == null ) - throw new ArgumentNullException( "context" ); - + m_dataGridContext = dataGridContext; m_generator = generator; - m_context = context; m_itemCount = generator.ItemCount; } @@ -48,7 +46,7 @@ namespace Xceed.Wpf.DataGrid { get { - return m_context; + return m_dataGridContext; } } @@ -65,7 +63,7 @@ namespace Xceed.Wpf.DataGrid base.CleanGeneratorNode(); m_generator.CleanupGenerator( true ); - m_context.CleanDataGridContext(); + m_dataGridContext.CleanDataGridContext(); m_generator = null; } @@ -75,8 +73,8 @@ namespace Xceed.Wpf.DataGrid m_itemCount = m_generator.ItemCount; } + private readonly DataGridContext m_dataGridContext; private CustomItemContainerGenerator m_generator; - private DataGridContext m_context; private int m_itemCount; } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GeneratorNode.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GeneratorNode.cs index c2a5ef90..193cde13 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GeneratorNode.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GeneratorNode.cs @@ -111,9 +111,9 @@ namespace Xceed.Wpf.DataGrid { delta = this.AdjustItemCountOverride( delta ); - if( ( this.Parent != null ) && ( delta != 0 ) ) + if( ( this.Parent != null ) && ( delta != 0 ) ) { - this.Parent.AdjustItemCount( delta); + this.Parent.AdjustItemCount( delta ); } } @@ -123,7 +123,7 @@ namespace Xceed.Wpf.DataGrid if( ( this.Parent != null ) && ( delta != 0 ) ) { - this.Parent.AdjustLeafCount( delta); + this.Parent.AdjustLeafCount( delta ); } } @@ -143,10 +143,11 @@ namespace Xceed.Wpf.DataGrid protected void OnExpansionStateChanged( bool newExpansionState, int itemOffset, int count ) { - if( this.ExpansionStateChanged != null ) - { - this.ExpansionStateChanged( this, new ExpansionStateChangedEventArgs( newExpansionState, itemOffset, count ) ); - } + var handler = this.ExpansionStateChanged; + if( handler == null ) + return; + + handler.Invoke( this, new ExpansionStateChangedEventArgs( newExpansionState, itemOffset, count ) ); } } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GeneratorNodeFactory.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GeneratorNodeFactory.cs index 38c40e8a..be0703fc 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GeneratorNodeFactory.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GeneratorNodeFactory.cs @@ -29,6 +29,7 @@ namespace Xceed.Wpf.DataGrid { public GeneratorNodeFactory( NotifyCollectionChangedEventHandler itemsChangedHandler, NotifyCollectionChangedEventHandler groupsChangedHandler, + NotifyCollectionChangedEventHandler headersFootersChangedHandler, EventHandler expansionStateChangedHandler, EventHandler isExpandedChangingHandler, EventHandler isExpandedChangedHandler, @@ -40,6 +41,9 @@ namespace Xceed.Wpf.DataGrid if( groupsChangedHandler == null ) throw new ArgumentNullException( "groupsChangedHandler" ); + if( headersFootersChangedHandler == null ) + throw new ArgumentNullException( "headersFootersChangedHandler" ); + if( expansionStateChangedHandler == null ) throw new ArgumentNullException( "expansionStateChangedHandler" ); @@ -51,6 +55,7 @@ namespace Xceed.Wpf.DataGrid m_itemsChangedHandler = itemsChangedHandler; m_groupsChangedHandler = groupsChangedHandler; + m_headersFootersChangedHandler = headersFootersChangedHandler; m_expansionStateChangedHandler = expansionStateChangedHandler; m_isExpandedChangingHandler = isExpandedChangingHandler; m_isExpandedChangedHandler = isExpandedChangedHandler; @@ -102,7 +107,7 @@ namespace Xceed.Wpf.DataGrid } node.Next = next; - node.IsExpanded = groupConfig.InitiallyExpanded; + node.SetIsExpandedAtInitialization( groupConfig.InitiallyExpanded ); if( !collectionViewGroup.IsBottomLevel ) { @@ -129,11 +134,9 @@ namespace Xceed.Wpf.DataGrid IList collection, GeneratorNode parent, GeneratorNode previous, - GeneratorNode next, - CustomItemContainerGenerator generator ) + GeneratorNode next ) { Debug.Assert( collection != null, "collection cannot be null for CreateItemsGeneratorNode()" ); - Debug.Assert( generator != null ); INotifyCollectionChanged notifyCollection = collection as INotifyCollectionChanged; @@ -153,7 +156,6 @@ namespace Xceed.Wpf.DataGrid this.SetupCollectionGeneratorNode( node, parent, previous, next ); - node.AdjustLeafCount( node.Items.Count ); return node; @@ -339,9 +341,7 @@ namespace Xceed.Wpf.DataGrid private void UnregisterNodeCollectionChanged( INotifyCollectionChanged source ) { - bool existed = m_nodesCollectionChangedEventHandlers.Remove( source ); - - if( existed ) + if( m_nodesCollectionChangedEventHandlers.Remove( source ) ) { CollectionChangedEventManager.RemoveListener( source, this ); } @@ -350,14 +350,22 @@ namespace Xceed.Wpf.DataGrid #region IWeakEventListener Members bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) + { + return this.OnReceiveWeakEvent( managerType, sender, e ); + } + + protected virtual bool OnReceiveWeakEvent( Type managerType, object sender, EventArgs e ) { if( managerType == typeof( CollectionChangedEventManager ) ) { this.OnCollectionChanged( ( INotifyCollectionChanged )sender, ( NotifyCollectionChangedEventArgs )e ); - return true; + } + else + { + return false; } - return false; + return true; } private void OnCollectionChanged( INotifyCollectionChanged source, NotifyCollectionChangedEventArgs e ) @@ -371,17 +379,9 @@ namespace Xceed.Wpf.DataGrid } else if( m_headersFootersMapping.TryGetValue( source, out nodeList ) ) { - try - { - foreach( var node in nodeList ) - { - m_itemsChangedHandler.Invoke( node, e ); - } - } - catch( Exception ex ) - { - throw new DataGridInternalException( ex.Message, ex, this.DataGridControl ); - } + Debug.Assert( nodeList.Count > 0 ); + + m_headersFootersChangedHandler.Invoke( nodeList, e ); } } @@ -389,11 +389,12 @@ namespace Xceed.Wpf.DataGrid #region Private Fields - private readonly NotifyCollectionChangedEventHandler m_itemsChangedHandler; // = null - private readonly NotifyCollectionChangedEventHandler m_groupsChangedHandler; // = null - private readonly EventHandler m_expansionStateChangedHandler; // = null - private readonly EventHandler m_isExpandedChangedHandler; // = null - private readonly EventHandler m_isExpandedChangingHandler; // = null + private readonly NotifyCollectionChangedEventHandler m_itemsChangedHandler; + private readonly NotifyCollectionChangedEventHandler m_groupsChangedHandler; + private readonly NotifyCollectionChangedEventHandler m_headersFootersChangedHandler; + private readonly EventHandler m_expansionStateChangedHandler; + private readonly EventHandler m_isExpandedChangedHandler; + private readonly EventHandler m_isExpandedChangingHandler; private readonly Dictionary> m_headersFootersMapping = new Dictionary>( 32 ); private readonly Dictionary m_nodesCollectionChangedEventHandlers = new Dictionary( 32 ); diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GeneratorNodeHelper.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GeneratorNodeHelper.cs index 6423c1d7..1a448bf4 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GeneratorNodeHelper.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GeneratorNodeHelper.cs @@ -15,224 +15,130 @@ ***********************************************************************************/ using System; -using System.Collections; +using System.Diagnostics; using System.Windows; using System.Windows.Data; namespace Xceed.Wpf.DataGrid { - internal class GeneratorNodeHelper + internal sealed class GeneratorNodeHelper { - public GeneratorNodeHelper( GeneratorNode initialPointer, int index, int sourceDataIndex ) + internal GeneratorNodeHelper( GeneratorNode startNode, int index, int sourceDataIndex ) { - if( initialPointer == null ) - throw new ArgumentNullException( "initialPointer" ); + if( startNode == null ) + throw new ArgumentNullException( "startNode" ); - m_currentNode = initialPointer; - m_index = index; - m_sourceDataIndex = sourceDataIndex; + m_state = new State( startNode, index, sourceDataIndex ); } - //------------- - // Properties - - public GeneratorNode CurrentNode + internal GeneratorNode CurrentNode { get { - return m_currentNode; + return m_state.Node; } } - public int Index + internal int Index { get { - return m_index; + return m_state.Index; } } - public int SourceDataIndex + internal int SourceDataIndex { get { - return m_sourceDataIndex; + return m_state.DataIndex; } } - //------------- - // Methods - - public bool MoveToNext() + internal bool MoveToNext() { - if( m_currentNode.Next != null ) - { - GroupGeneratorNode groupNode = m_currentNode as GroupGeneratorNode; - - if( groupNode != null ) - { - m_sourceDataIndex += groupNode.TotalLeafCount; - } + var success = GeneratorNodeHelper.MoveToNext( ref m_state ); - m_index += m_currentNode.ItemCount; - m_currentNode = m_currentNode.Next; - return true; - } + this.EnsureState(); - return false; + return success; } - public bool MoveToNextBy( int count ) + internal bool MoveToNextBy( int count ) { - GeneratorNode originalNode = m_currentNode; - int originalIndex = m_index; - int originalSourceDataIndex = m_sourceDataIndex; + var success = GeneratorNodeHelper.MoveToNext( ref m_state, count ); - for( int i = 0; i < count; i++ ) - { - //if we are not capable of moving forward to the item specified, problem.... throw. - if( !this.MoveToNext() ) - { - m_currentNode = originalNode; - m_index = originalIndex; - m_sourceDataIndex = originalSourceDataIndex; - return false; - } - } + this.EnsureState(); - return true; + return success; } - //internal use only - public bool MoveToPrevious() + internal bool MoveToPrevious() { - if( m_currentNode.Previous != null ) - { - m_currentNode = m_currentNode.Previous; - GroupGeneratorNode groupNode = m_currentNode as GroupGeneratorNode; + var success = GeneratorNodeHelper.MoveToPrevious( ref m_state ); - if( groupNode != null ) - { - m_sourceDataIndex -= groupNode.TotalLeafCount; - } + this.EnsureState(); - m_index -= m_currentNode.ItemCount; - return true; - } - - return false; + return success; } - public bool MoveToFirst() + internal bool MoveToFirst() { - //this function stays at the same level and moves to the first node - while( this.MoveToPrevious() ) - { - } + GeneratorNodeHelper.MoveToFirst( ref m_state ); + + this.EnsureState(); return true; } - public bool MoveToEnd() + internal bool MoveToEnd() { - //this function stays at the same level and moves to the end - while( this.MoveToNext() ) + // We call MoveToNext instead of MoveToEnd because MoveToEnd includes the indexes of the last node. + while( GeneratorNodeHelper.MoveToNext( ref m_state ) ) { } - return true; - } - - public bool MoveToChild() - { - return this.MoveToChild( true ); - } + this.EnsureState(); - public bool MoveToChild( bool skipItemLessGroupNodes ) - { - GroupGeneratorNode groupNode = m_currentNode as GroupGeneratorNode; - - if( ( groupNode == null ) || ( groupNode.Child == null ) ) - return false; - - if( ( skipItemLessGroupNodes ) && ( !( groupNode.ItemCount > 0 ) ) ) - return false; - - m_currentNode = groupNode.Child; return true; } - public bool MoveToParent() + internal bool MoveToChild( bool skipItemLessGroupNodes ) { - GeneratorNode originalNode = m_currentNode; - int originalIndex = m_index; - int originalSourceDataIndex = m_sourceDataIndex; - - //move until we arrive at the first of the linked list. - while( this.MoveToPrevious() ) - { - } + var success = GeneratorNodeHelper.MoveToChild( ref m_state, skipItemLessGroupNodes ); - //if the first does not have a parent, then... error. - if( m_currentNode.Parent != null ) - { - m_currentNode = m_currentNode.Parent; - return true; - } + this.EnsureState(); - //if there was an error, revert to the original node; - m_currentNode = originalNode; - m_index = originalIndex; - m_sourceDataIndex = originalSourceDataIndex; - return false; + return success; } - public bool MoveToFollowing() + internal bool MoveToParent() { - bool retval = false; - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_currentNode, m_index, m_sourceDataIndex ); + var success = GeneratorNodeHelper.MoveToParent( ref m_state ); - while( !retval ) - { - retval = nodeHelper.MoveToNext(); + this.EnsureState(); - if( !retval ) - { - if( !nodeHelper.MoveToParent() ) - { - //cannot move to parent and could not move to next, this is the end of the chain. - break; - } - } - } - - if( retval ) - { - m_currentNode = nodeHelper.CurrentNode; - m_index = nodeHelper.Index; - m_sourceDataIndex = nodeHelper.SourceDataIndex; - } - - return retval; + return success; } - public bool InsertAfter( GeneratorNode insert ) + internal bool InsertAfter( GeneratorNode insert ) { if( insert == null ) throw new DataGridInternalException( "GeneratorNode is null." ); - int insertionCount; - int chainLength; - GeneratorNode insertLast = GeneratorNodeHelper.EvaluateChain( insert, out insertionCount, out chainLength ); + var insertionCount = default( int ); + var chainLength = default( int ); + var insertLast = GeneratorNodeHelper.EvaluateChain( insert, out insertionCount, out chainLength ); - if( m_currentNode.Next != null ) + var nextNode = m_state.Node.Next; + if( nextNode != null ) { - m_currentNode.Next.Previous = insertLast; + nextNode.Previous = insertLast; } - insertLast.Next = m_currentNode.Next; - insert.Previous = m_currentNode; - m_currentNode.Next = insert; + insertLast.Next = nextNode; + insert.Previous = m_state.Node; + m_state.Node.Next = insert; // Move the current node to the last node inserted if( !this.MoveToNextBy( chainLength ) ) @@ -241,527 +147,362 @@ namespace Xceed.Wpf.DataGrid return true; } - public bool InsertBefore( GeneratorNode insert ) + internal bool InsertBefore( GeneratorNode insert ) { if( insert == null ) throw new DataGridInternalException( "GeneratorNode is null" ); - int insertionCount; - int chainLength; - GeneratorNode insertLast = GeneratorNodeHelper.EvaluateChain( insert, out insertionCount, out chainLength ); - GeneratorNode previous = m_currentNode.Previous; + var insertionCount = default( int ); + var chainLength = default( int ); + var insertLast = GeneratorNodeHelper.EvaluateChain( insert, out insertionCount, out chainLength ); - if( previous != null ) + var previousNode = m_state.Node.Previous; + if( previousNode != null ) { - previous.Next = insert; + previousNode.Next = insert; } - insert.Previous = previous; - m_currentNode.Previous = insertLast; - insertLast.Next = m_currentNode; - - GroupGeneratorNode parentGroup = insert.Parent as GroupGeneratorNode; + insert.Previous = previousNode; + m_state.Node.Previous = insertLast; + insertLast.Next = m_state.Node; + var parentGroup = insert.Parent as GroupGeneratorNode; if( parentGroup != null ) { - if( parentGroup.Child == m_currentNode ) + if( parentGroup.Child == m_state.Node ) { parentGroup.Child = insert; } } // Move the current to the first item inserted. - // No need to change m_index, m_sourceDataIndex since they will still be with the correct value. - m_currentNode = insert; - return true; - } - - public static GeneratorNode EvaluateChain( GeneratorNode chainStart, out int totalChildCount, out int chainLength ) - { - //if we insert a chain of nodes, this GeneratorNodeHelper will help us - GeneratorNodeHelper newHelper = new GeneratorNodeHelper( chainStart, 0, 0 ); + // No need to update the indexes since they will still be with the correct value. + m_state.Node = insert; - //first determine the total number of childs from this "node" - totalChildCount = 0; - chainLength = 0; + this.EnsureState(); - do - { - totalChildCount += newHelper.CurrentNode.ItemCount; - chainLength++; - } - while( newHelper.MoveToNext() ); - - //then, since we moved at the end of the "chain" - return newHelper.CurrentNode; + return true; } - //FindItem skips over itemless nodes. - public int FindItem( object item ) + internal int FindItem( object item ) { - //finding items can only be done in "forward" direction - int retval = -1; - - GeneratorNode originalNode = m_currentNode; - int originalIndex = m_index; - int originalSourceDataIndex = m_sourceDataIndex; + var current = m_state; - while( retval == -1 ) + while( true ) { - ItemsGeneratorNode itemsNode = m_currentNode as ItemsGeneratorNode; - + var itemsNode = current.Node as ItemsGeneratorNode; if( itemsNode != null ) { - int tmpIndex = itemsNode.Items.IndexOf( item ); - if( tmpIndex > -1 ) + var index = itemsNode.Items.IndexOf( item ); + if( index >= 0 ) { - tmpIndex += itemsNode.CountDetailsBeforeDataIndex( tmpIndex ); - //item is directly from this items node... then return the appropriate index! - retval = m_index + tmpIndex; - break; - } - else - { - //if the item is from a detail, then I don't want to "use" it!!! - retval = -1; - //but continue looping.... to find occurances of this item somewhere else in the tree + index += itemsNode.CountDetailsBeforeDataIndex( index ); + + // Item is directly from this items node... then return the appropriate index! + m_state = current; + + this.EnsureState(); + + return index + current.Index; } + + // If the item is from a detail, then I don't want to "use" it!!! + // but continue looping.... to find occurances of this item somewhere else in the tree. } else { - CollectionGeneratorNode collectionNode = m_currentNode as CollectionGeneratorNode; - + var collectionNode = current.Node as CollectionGeneratorNode; if( collectionNode != null ) { - int tmpIndex = collectionNode.IndexOf( item ); - - if( tmpIndex != -1 ) + var index = collectionNode.IndexOf( item ); + if( index >= 0 ) { - retval = m_index + tmpIndex; - break; + m_state = current; + + this.EnsureState(); + + return index + current.Index; } } } - //if we reach this point, it's because the item we are looking - //for is not in this node... Try to access the child - if( this.MoveToChild() ) - continue; - - //if we reach this point, it's because we have no child... - if( this.MoveToNext() ) - continue; - - //final try, try "advancing" to the next item. - if( this.MoveToFollowing() ) - continue; - - //up to this, we are in an endpoint, we failed. - break; - } - - if( retval == -1 ) - { - m_currentNode = originalNode; - m_index = originalIndex; - m_sourceDataIndex = originalSourceDataIndex; + // If we reach this point, it's because the item we are looking + // for is not in this node... Try to access the child + if( !GeneratorNodeHelper.MoveToChild( ref current ) ) + { + // Try "advancing" to the next item. + if( !GeneratorNodeHelper.MoveToFollowing( ref current ) ) + break; + } } - return retval; + return -1; } - public object FindIndex( int index ) + internal object FindIndex( int index ) { - //WARNING: this method only searches forward - - GeneratorNode originalNode = m_currentNode; - int originalIndex = m_index; - int originalSourceDataIndex = m_sourceDataIndex; + var current = m_state; - do + while( true ) { - if( index < ( m_index + m_currentNode.ItemCount ) ) + if( index < current.Index + current.Node.ItemCount ) { - CollectionGeneratorNode itemsNode = m_currentNode as CollectionGeneratorNode; - + var itemsNode = current.Node as CollectionGeneratorNode; if( itemsNode != null ) { - return itemsNode.GetAt( index - m_index ); - } - else // not an Items Node, then try to move to child... - { - //if it fails, then quit loop with failure - if( !this.MoveToChild() ) - { - break; - } + m_state = current; + + this.EnsureState(); + + return itemsNode.GetAt( index - current.Index ); } + + if( !GeneratorNodeHelper.MoveToChild( ref current ) ) + break; } else { - //if we reach this point, it's because the item we are looking - //for is not in this node... Try to access the child - - //No need to check for childs, since the condition above would catch it (childs part of ItemCount). - - if( this.MoveToNext() ) - continue; - - //final try, try "advancing" to the next item. - if( this.MoveToFollowing() ) - continue; - - //up to this, we are in an endpoint, we failed. - break; + // If we reach this point, it's because the item we are looking for is not in this node... Try to access the child. + // No need to check for childs, since the condition above would catch it (childs part of ItemCount). + if( !GeneratorNodeHelper.MoveToFollowing( ref current ) ) + break; } } - while( true ); - m_currentNode = originalNode; - m_index = originalIndex; - m_sourceDataIndex = originalSourceDataIndex; return null; } - public bool ReverseCalculateIndex() + internal bool FindNode( GeneratorNode node ) { - // index need to be 0, as I will use the value from the index once I backtracked all the way to the root. - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( this.CurrentNode, 0, 0 ); + if( node == null ) + throw new ArgumentNullException( "node" ); - while( ( nodeHelper.CurrentNode.Previous != null ) || ( nodeHelper.CurrentNode.Parent != null ) ) - { - if( !nodeHelper.MoveToPrevious() ) - { - nodeHelper.MoveToParent(); - } - } + var success = GeneratorNodeHelper.FindNode( ref m_state, node ); - m_index = Math.Abs( nodeHelper.Index ); - m_sourceDataIndex = Math.Abs( nodeHelper.SourceDataIndex ); - return true; + this.EnsureState(); + + return success; } - public bool FindNodeForIndex( int index ) + internal bool FindNodeForIndex( int index ) { - GeneratorNode originalNode = m_currentNode; - int originalIndex = m_index; - int originalSourceDataIndex = m_sourceDataIndex; - - //The algo is a single drill-down... for optimized performance.. - //It first tries to go Horizontally in the tree and then drills-down it can. - - do - { - int itemCount = m_currentNode.ItemCount; + var success = GeneratorNodeHelper.FindNodeForIndex( ref m_state, index ); - //verify if the current node contains ( directly or its children ) the required index - if( index < ( m_index + itemCount ) ) - { - //a Group node is the only node that can Have Children is by definition empty... let's dig deeper. - //If we try to dig deeper and fail... - if( !this.MoveToChild() ) - { - //if we cannot travel deeper, then this node is the closest we get... - return true; - } - } - else if( ( index == m_index ) && ( itemCount != 0 ) ) - { - return true; - } - else - { - //Move to the NextNode in the list... - if( !this.MoveToNext() ) - break; - } - } - while( true ); + this.EnsureState(); - m_currentNode = originalNode; - m_index = originalIndex; - m_sourceDataIndex = originalSourceDataIndex; - return false; + return success; } - public bool MoveForward() + //Note: this function will not check for the presence of the item in the details for Items nodes. + internal bool AbsoluteFindItem( object item ) { - bool recurseGroup = true; - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_currentNode, m_index, m_sourceDataIndex ); + // This method will search through nodes, even those collapsed for the item. + var current = m_state; - do + while( true ) { - GroupGeneratorNode groupNode = nodeHelper.CurrentNode as GroupGeneratorNode; + var itemsNode = current.Node as CollectionGeneratorNode; + if( ( itemsNode != null ) && itemsNode.Items.Contains( item ) ) + break; - if( ( groupNode == null ) && ( nodeHelper.CurrentNode != m_currentNode ) && ( nodeHelper.CurrentNode.ItemCount != 0 ) ) + // If we reach this point, it's because the item we are looking + // for is not in this node... Try to access the child + if( !GeneratorNodeHelper.MoveToChild( ref current, false ) ) { - m_currentNode = nodeHelper.CurrentNode; - m_index = nodeHelper.Index; - m_sourceDataIndex = nodeHelper.SourceDataIndex; - return true; + // Try "advancing" to the next item. + if( !GeneratorNodeHelper.MoveToFollowing( ref current ) ) + return false; } + } - if( ( recurseGroup ) && ( nodeHelper.MoveToChild() ) ) - continue; + m_state = current; - recurseGroup = true; + this.EnsureState(); - if( nodeHelper.MoveToNext() ) - continue; - - if( nodeHelper.MoveToParent() ) - { - recurseGroup = false; - continue; - } - - break; - } - while( true ); - - return false; + return true; } - public bool MoveBackward() + //Note: this function will not check for the presence of the group in the details for Items nodes. + internal bool FindGroup( CollectionViewGroup group ) { - bool recurseGroup = true; - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_currentNode, m_index, m_sourceDataIndex ); + if( group == null ) + return false; - do - { - GroupGeneratorNode groupNode = nodeHelper.CurrentNode as GroupGeneratorNode; + var current = m_state; - if( ( groupNode == null ) && ( nodeHelper.CurrentNode != m_currentNode ) && ( nodeHelper.CurrentNode.ItemCount != 0 ) ) + while( true ) + { + var groupNode = current.Node as GroupGeneratorNode; + if( groupNode != null ) { - m_currentNode = nodeHelper.CurrentNode; - m_index = nodeHelper.Index; - m_sourceDataIndex = nodeHelper.SourceDataIndex; - return true; - } + if( groupNode.CollectionViewGroup == group ) + break; - if( ( recurseGroup ) && ( nodeHelper.MoveToChild() ) ) + if( !groupNode.CollectionViewGroup.IsBottomLevel ) + { + if( !GeneratorNodeHelper.MoveToChild( ref current, false ) ) + return false; + } + else + { + if( !GeneratorNodeHelper.MoveToFollowing( ref current ) ) + return false; + } + } + else { - nodeHelper.MoveToEnd(); - continue; + // There is nothing under a non GroupGeneratorNode, try to move Next node in the list. + if( !GeneratorNodeHelper.MoveToFollowing( ref current ) ) + return false; } + } - recurseGroup = true; + m_state = current; - if( nodeHelper.MoveToPrevious() ) - continue; + this.EnsureState(); + return true; + } - if( nodeHelper.MoveToParent() ) - { - recurseGroup = false; - continue; - } - - break; - } - while( true ); + internal void ReverseCalculateIndex() + { + m_state = GeneratorNodeHelper.FindNodeLocation( m_state.Node ); - return false; + this.EnsureState(); } - //Note: this function will not check for the presence of the item in the details for Items nodes. - public bool AbsoluteFindItem( object item ) + internal bool MoveForward() { - //this method will search through nodes, even those collapsed for the item - //finding items can only be done in "forward" direction - GeneratorNode originalNode = m_currentNode; - int originalIndex = m_index; - int originalSourceDataIndex = m_sourceDataIndex; + var startNode = m_state.Node; - do + while( true ) { - CollectionGeneratorNode itemsNode = m_currentNode as CollectionGeneratorNode; + if( !( m_state.Node is GroupGeneratorNode ) && ( m_state.Node != startNode ) && ( m_state.Node.ItemCount != 0 ) ) + break; - if( itemsNode != null ) + if( !GeneratorNodeHelper.MoveToChild( ref m_state ) ) { - if( itemsNode.Items.Contains( item ) ) - return true; + if( !GeneratorNodeHelper.MoveToFollowing( ref m_state ) ) + return false; } + } - //if we reach this point, it's because the item we are looking - //for is not in this node... Try to access the child - if( this.MoveToChild() ) - continue; - - //if we reach this point, it's because we have no child... - if( this.MoveToNext() ) - continue; - - //final try, try "advancing" to the next item. - if( this.MoveToFollowing() ) - continue; - - //up to this, we are in an endpoint, we failed. - break; - } while( true ); + this.EnsureState(); - m_currentNode = originalNode; - m_index = originalIndex; - m_sourceDataIndex = originalSourceDataIndex; - return false; + return true; } - //Note: this function will not check for the presence of the group in the details for Items nodes. - public bool FindGroup( CollectionViewGroup group ) + internal bool MoveBackward() { - if( group == null ) - return false; - - GeneratorNode originalNode = m_currentNode; - int originalIndex = m_index; - int originalSourceDataIndex = m_sourceDataIndex; + var startNode = m_state.Node; - do + while( true ) { - GroupGeneratorNode groupNode = m_currentNode as GroupGeneratorNode; - if( groupNode != null ) - { - if( groupNode.CollectionViewGroup == group ) - return true; + if( !( m_state.Node is GroupGeneratorNode ) && ( m_state.Node != startNode ) && ( m_state.Node.ItemCount != 0 ) ) + break; - if( !groupNode.CollectionViewGroup.IsBottomLevel ) - { - if( !this.MoveToChild( false ) ) - { - break; - } - } - else - { - if( !this.MoveToFollowing() ) - { - break; - } - } + if( !GeneratorNodeHelper.MoveToChild( ref m_state ) ) + { + if( !GeneratorNodeHelper.MoveToPreceding( ref m_state ) ) + return false; } else { - //There can be nothing under a non-GroupGeneratorNode, try to move Next node in the list. - if( !this.MoveToFollowing() ) - { - break; - } + GeneratorNodeHelper.MoveToEnd( ref m_state ); } - } while( true ); + } + + this.EnsureState(); - m_currentNode = originalNode; - m_index = originalIndex; - m_sourceDataIndex = originalSourceDataIndex; - return false; + return true; } - //This method cannot be used for groups. - //This method will search for items independently of the Expanded/Collpased status of GroupGeneratorNodes - public bool Contains( object item ) + // This method cannot be used for groups. + // This method will search for items independently of the Expanded/Collapsed status of GroupGeneratorNodes. + internal bool Contains( object item ) { - bool skipCollectionGeneratorNodeCheck = false; + var current = m_state; + var found = false; + var skipCollectionGeneratorNodeCheck = false; - do + while( true ) { - HeadersFootersGeneratorNode headersFootersNode = m_currentNode as HeadersFootersGeneratorNode; skipCollectionGeneratorNodeCheck = false; - //If the node is a HeadersFootersGeneratorNode, do some specific handling. - if( headersFootersNode != null ) + var headersFootersNode = current.Node as HeadersFootersGeneratorNode; + if( ( headersFootersNode != null ) && ( item is GroupHeaderFooterItem ) ) { - //If the item passed to the function is a GroupHeaderFooterItem, then its because we are looking for a GroupHeader/Footer - if( item.GetType() == typeof( GroupHeaderFooterItem ) ) - { - GroupHeaderFooterItem groupHeaderFooterItem = ( GroupHeaderFooterItem )item; + var groupHeaderFooterItem = ( GroupHeaderFooterItem )item; + var parentGroup = headersFootersNode.Parent as GroupGeneratorNode; - //Determine the parent node/collectionViewGroup - GroupGeneratorNode parentGroup = headersFootersNode.Parent as GroupGeneratorNode; - - if( parentGroup != null ) - { - if( groupHeaderFooterItem.Group == parentGroup.CollectionViewGroup ) - { - if( headersFootersNode.Items.Contains( groupHeaderFooterItem.Template ) ) - return true; - } - } - //If there is no parent node, then its because the current HeadersFootersGeneratorNode is not a GroupHeaders/Footers node (FixedHeaders/Fotoers or Headers/Footers). - - skipCollectionGeneratorNodeCheck = true; //force skip CollectionGeneratorNode verification, this is to limit amount of job done by loop body. + if( ( parentGroup != null ) && ( parentGroup.CollectionViewGroup == groupHeaderFooterItem.Group ) && headersFootersNode.Items.Contains( groupHeaderFooterItem.Template ) ) + { + found = true; + break; } - //If the item passed is not a GroupHeaderFooterItem, not need to do specific processing, reverting to "Common" algo. + // If there is no parent node, then its because the current HeadersFootersGeneratorNode is not a GroupHeaders/Footers node (FixedHeaders/Footers or Headers/Footers). + skipCollectionGeneratorNodeCheck = true; // force skip CollectionGeneratorNode verification, this is to limit amount of job done by loop body. } if( !skipCollectionGeneratorNodeCheck ) { - CollectionGeneratorNode collectionNode = m_currentNode as CollectionGeneratorNode; - + var collectionNode = current.Node as CollectionGeneratorNode; if( collectionNode != null ) { // When dealing with a DataView, the DataView's IList's Contains implementation will return false // for a dataRowView which is in edition and was modified even though it is really part of the collection. // Therefore, we must use a for loop of Object.Equals method calls. - System.Data.DataRowView dataRowViewItem = item as System.Data.DataRowView; - + var dataRowViewItem = item as System.Data.DataRowView; if( dataRowViewItem != null ) { - IList items = collectionNode.Items; - int itemsCount = items.Count; - - System.Data.DataRow itemDataRow = dataRowViewItem.Row; + var items = collectionNode.Items; + var itemsCount = items.Count; + var itemDataRow = dataRowViewItem.Row; for( int i = 0; i < itemsCount; i++ ) { - System.Data.DataRowView currentDataRowView = items[ i ] as System.Data.DataRowView; - + var currentDataRowView = items[ i ] as System.Data.DataRowView; if( ( currentDataRowView != null ) && ( itemDataRow == currentDataRowView.Row ) ) - return true; + { + found = true; + break; + } } + + if( found ) + break; } else { - //Since the GetAt() methods can be overriden to compensate for the Expand/Collapse status of Groups + // Since the GetAt() methods can be overriden to compensate for the Expand/Collapse status of Groups // AND the details features, accessing the collection directly prevent pre-processing of the content of the collection node. if( collectionNode.Items.Contains( item ) ) { - //if the item is from a detail, then I don't want to "use" it!!! - return true; + found = true; + break; } } } } - //if we reach this point, it's because the item we are looking - //for is not in this node... Try to access the child - //Note: Since I want to search independently of the Expand/Collapse status, - //pass false to the method to systematically visit childs. - if( this.MoveToChild( false ) ) + if( GeneratorNodeHelper.MoveToChild( ref current, false ) ) continue; - //if we reach this point, it's because we have no child... - if( this.MoveToNext() ) + if( GeneratorNodeHelper.MoveToFollowing( ref current ) ) continue; - //final try, try "advancing" to the next item. - if( this.MoveToFollowing() ) - continue; - - //up to this, we are in an endpoint, we failed. break; - } while( true ); + } - return false; - } + m_state = current; - //------------- - // Data Members + this.EnsureState(); - private GeneratorNode m_currentNode; // = null - private int m_index; - private int m_sourceDataIndex; + return found; + } - public void ProcessVisit( + internal void ProcessVisit( DataGridContext sourceContext, int minIndex, int maxIndex, @@ -773,14 +514,11 @@ namespace Xceed.Wpf.DataGrid visitWasStopped = false; // This is used only for DataGridContextVisitorType.ItemsBlock - int startSourceDataItemIndex = -1; - int endSourceDataItemIndex = -1; + var startSourceDataItemIndex = -1; + var endSourceDataItemIndex = -1; if( minIndex < 0 ) - { - DataGridException.ThrowSystemException( "The minimum index must be greater than or equal to zero.", - typeof( ArgumentException ), sourceContext.DataGridControl.Name, "minIndex" ); - } + throw DataGridException.Create( "The minimum index must be greater than or equal to zero.", sourceContext.DataGridControl, "minIndex" ); if( ( visitorType & DataGridContextVisitorType.DataGridContext ) == DataGridContextVisitorType.DataGridContext ) { @@ -792,43 +530,42 @@ namespace Xceed.Wpf.DataGrid //Take a shortcut, if the visit is made only for contexts, and there is no child contexts //return right away. - bool containsDetails = false; + var containsDetails = false; - foreach( DataGridContext childContext in sourceContext.GetChildContexts() ) + foreach( var childContext in sourceContext.GetChildContextsCore() ) { containsDetails = true; break; } - bool processed = false; + var processed = false; + var current = m_state; - do + while( true ) { - //resets the flag that indicates if the node was already processed processed = false; - int itemCount = this.CurrentNode.ItemCount; + var itemCount = current.Node.ItemCount; //If the whole current node is below the minIndex, jump over it. - if( ( this.Index + ( itemCount - 1 ) ) < minIndex ) + if( ( current.Index + ( itemCount - 1 ) ) < minIndex ) { processed = true; } //when the index to visit exceeds the range defined, exit the loop. - if( this.Index > maxIndex ) + if( current.Index > maxIndex ) break; - int minForNode = Math.Max( 0, minIndex - this.Index ); // this will give the base offset within the node where to start the visitating! - int maxForNode = Math.Min( itemCount - 1, maxIndex - this.Index ); //this will five the max offset within this node to visit (protected against overlfow ) + var minForNode = Math.Max( 0, minIndex - current.Index ); // this will give the base offset within the node where to start the visitating! + var maxForNode = Math.Min( itemCount - 1, maxIndex - current.Index ); //this will five the max offset within this node to visit (protected against overlfow ) if( !processed ) { - HeadersFootersGeneratorNode headersNode = this.CurrentNode as HeadersFootersGeneratorNode; - + var headersNode = current.Node as HeadersFootersGeneratorNode; if( headersNode != null ) { - bool isHeaderFooter = ( headersNode.Parent == null ); + var isHeaderFooter = ( headersNode.Parent == null ); //If the node is a Headers or Footers node AND the visitorType does not contain HeadersFooters if( ( isHeaderFooter ) && ( ( visitorType & DataGridContextVisitorType.HeadersFooters ) == DataGridContextVisitorType.HeadersFooters ) ) @@ -846,8 +583,7 @@ namespace Xceed.Wpf.DataGrid if( !processed ) { - ItemsGeneratorNode itemsNode = this.CurrentNode as ItemsGeneratorNode; - + var itemsNode = current.Node as ItemsGeneratorNode; if( itemsNode != null ) { if( ( visitorType & DataGridContextVisitorType.ItemsBlock ) == DataGridContextVisitorType.ItemsBlock ) @@ -855,7 +591,7 @@ namespace Xceed.Wpf.DataGrid GeneratorNodeHelper.ProcessItemsNodeBlockVisit( itemsNode, sourceContext, minForNode, maxForNode, - visitor, visitorType, visitDetails, containsDetails, m_sourceDataIndex, + visitor, visitorType, visitDetails, containsDetails, current.DataIndex, ref startSourceDataItemIndex, ref endSourceDataItemIndex, ref visitWasStopped ); } else if( ( ( visitDetails ) && ( containsDetails ) ) @@ -864,7 +600,7 @@ namespace Xceed.Wpf.DataGrid GeneratorNodeHelper.ProcessItemsNodeVisit( itemsNode, sourceContext, minForNode, maxForNode, - visitor, visitorType, visitDetails, m_sourceDataIndex, ref visitWasStopped ); + visitor, visitorType, visitDetails, current.DataIndex, ref visitWasStopped ); } processed = true; @@ -873,8 +609,7 @@ namespace Xceed.Wpf.DataGrid if( !processed ) { - GroupGeneratorNode groupNode = this.CurrentNode as GroupGeneratorNode; - + var groupNode = current.Node as GroupGeneratorNode; if( groupNode != null ) { if( ( visitorType & DataGridContextVisitorType.Groups ) == DataGridContextVisitorType.Groups ) @@ -894,31 +629,61 @@ namespace Xceed.Wpf.DataGrid } if( !processed ) - throw new DataGridInternalException( "Unable to process the visit.", sourceContext.DataGridControl ); + throw DataGridException.Create( "Unable to process the visit.", sourceContext.DataGridControl ); if( visitWasStopped ) break; - if( this.MoveToChild() ) + if( GeneratorNodeHelper.MoveToChild( ref current ) ) continue; - if( this.MoveToFollowing() ) + if( GeneratorNodeHelper.MoveToFollowing( ref current ) ) continue; break; } - while( true ); //loop is controled by continue and break statements. - if( ( visitorType & DataGridContextVisitorType.ItemsBlock ) == DataGridContextVisitorType.ItemsBlock ) { if( startSourceDataItemIndex != -1 ) { - bool stopVisit = false; + var stopVisit = false; visitor.Visit( sourceContext, startSourceDataItemIndex, endSourceDataItemIndex, ref stopVisit ); visitWasStopped = visitWasStopped || stopVisit; } } + + m_state = current; + + this.EnsureState(); + } + + internal static GeneratorNode EvaluateChain( GeneratorNode startNode, out int totalChildCount, out int chainLength ) + { + if( startNode == null ) + throw new ArgumentNullException( "startNode" ); + + var current = new State( startNode, 0, 0 ); + + totalChildCount = startNode.ItemCount; + chainLength = 1; + + while( true ) + { + if( !GeneratorNodeHelper.MoveToNext( ref current ) ) + break; + + totalChildCount += current.Node.ItemCount; + chainLength++; + } + + return current.Node; + } + + private void EnsureState() + { + if( m_state.Node == null ) + throw new DataGridInternalException(); } private static void ProcessItemsNodeBlockVisit( @@ -1030,7 +795,7 @@ namespace Xceed.Wpf.DataGrid int sourceDataItemIndex, ref bool stopVisit ) { - int runningIndex = minIndex; + var runningIndex = minIndex; sourceDataItemIndex += minIndex; int masterIndex; @@ -1039,19 +804,18 @@ namespace Xceed.Wpf.DataGrid while( runningIndex <= maxIndex ) { - DetailGeneratorNode detailNode = itemsNode.GetDetailNodeForIndex( runningIndex, out masterIndex, out detailStartIndex, out detailNodeIndex ); + var detailNode = itemsNode.GetDetailNodeForIndex( runningIndex, out masterIndex, out detailStartIndex, out detailNodeIndex ); if( detailNode != null ) { - int detailEndIndex = Math.Min( detailNode.ItemCount - 1, detailStartIndex + ( maxIndex - runningIndex ) ); + var detailEndIndex = Math.Min( detailNode.ItemCount - 1, detailStartIndex + ( maxIndex - runningIndex ) ); sourceDataItemIndex -= detailStartIndex; if( visitDetails ) { bool visitWasStopped; - ( ( IDataGridContextVisitable )detailNode.DetailGenerator ).AcceptVisitor( - detailStartIndex, detailEndIndex, visitor, visitorType, visitDetails, out visitWasStopped ); + ( ( IDataGridContextVisitable )detailNode.DetailGenerator ).AcceptVisitor( detailStartIndex, detailEndIndex, visitor, visitorType, visitDetails, out visitWasStopped ); stopVisit = stopVisit || visitWasStopped; @@ -1083,9 +847,9 @@ namespace Xceed.Wpf.DataGrid { for( int i = minIndex; i <= maxIndex; i++ ) { - object template = headersNode.GetAt( i ); + var template = headersNode.GetAt( i ); - GroupGeneratorNode groupNode = headersNode.Parent as GroupGeneratorNode; + var groupNode = headersNode.Parent as GroupGeneratorNode; if( groupNode != null ) { visitor.Visit( sourceContext, ( GroupHeaderFooterItem )template, ref stopVisit ); @@ -1100,5 +864,289 @@ namespace Xceed.Wpf.DataGrid } } + private static bool MoveToNext( ref State state ) + { + return GeneratorNodeHelper.MoveToNext( ref state, 1 ); + } + + private static bool MoveToNext( ref State state, int count ) + { + if( count <= 0 ) + return true; + + var node = state.Node; + var index = state.Index; + var dataIndex = state.DataIndex; + + for( int i = 0; i < count; i++ ) + { + var nextNode = node.Next; + if( nextNode == null ) + return false; + + var groupNode = node as GroupGeneratorNode; + if( groupNode != null ) + { + dataIndex += groupNode.TotalLeafCount; + } + + index += node.ItemCount; + node = nextNode; + } + + state.Node = node; + state.Index = index; + state.DataIndex = dataIndex; + + return true; + } + + private static bool MoveToPrevious( ref State state ) + { + var node = state.Node.Previous; + if( node == null ) + return false; + + state.Node = node; + state.Index -= node.ItemCount; + + var groupNode = node as GroupGeneratorNode; + if( groupNode != null ) + { + state.DataIndex -= groupNode.TotalLeafCount; + } + + return true; + } + + private static void MoveToFirst( ref State state ) + { + var node = state.Node.Previous; + if( node == null ) + return; + + var index = state.Index; + var dataIndex = state.DataIndex; + + while( true ) + { + var groupNode = node as GroupGeneratorNode; + if( groupNode != null ) + { + dataIndex -= groupNode.TotalLeafCount; + } + + index -= node.ItemCount; + + var target = node.Previous; + if( target == null ) + break; + + node = target; + } + + state.Node = node; + state.Index = index; + state.DataIndex = dataIndex; + } + + private static void MoveToEnd( ref State state ) + { + var node = state.Node; + if( node.Next == null ) + return; + + var index = state.Index; + var dataIndex = state.DataIndex; + + while( true ) + { + var groupNode = node as GroupGeneratorNode; + if( groupNode != null ) + { + dataIndex += groupNode.TotalLeafCount; + } + + index += node.ItemCount; + + var target = node.Next; + if( target == null ) + break; + + node = target; + } + + state.Node = node; + state.Index = index; + state.DataIndex = dataIndex; + } + + private static bool MoveToChild( ref State state ) + { + return GeneratorNodeHelper.MoveToChild( ref state, true ); + } + + private static bool MoveToChild( ref State state, bool skipItemLessGroupNodes ) + { + var groupNode = state.Node as GroupGeneratorNode; + if( ( groupNode == null ) || ( groupNode.Child == null ) ) + return false; + + if( ( skipItemLessGroupNodes ) && ( groupNode.ItemCount <= 0 ) ) + return false; + + state.Node = groupNode.Child; + + return true; + } + + private static bool MoveToParent( ref State state ) + { + if( state.Node.Level == 0 ) + return false; + + GeneratorNodeHelper.MoveToFirst( ref state ); + + state.Node = state.Node.Parent; + Debug.Assert( state.Node != null ); + + return true; + } + + private static bool MoveToFollowing( ref State state ) + { + while( !GeneratorNodeHelper.MoveToNext( ref state ) ) + { + if( !GeneratorNodeHelper.MoveToParent( ref state ) ) + return false; + } + + return true; + } + + private static bool MoveToPreceding( ref State state ) + { + while( !GeneratorNodeHelper.MoveToPrevious( ref state ) ) + { + if( !GeneratorNodeHelper.MoveToParent( ref state ) ) + return false; + } + + return true; + } + + private static State FindNodeLocation( GeneratorNode node ) + { + var state = new State( node, 0, 0 ); + + while( true ) + { + GeneratorNodeHelper.MoveToFirst( ref state ); + + if( !GeneratorNodeHelper.MoveToParent( ref state ) ) + break; + } + + Debug.Assert( state.Index <= 0 ); + Debug.Assert( state.DataIndex <= 0 ); + + return new State( node, -state.Index, -state.DataIndex ); + } + + private static bool FindNode( ref State state, GeneratorNode node ) + { + if( state.Node == node ) + return true; + + var from = state; + var fromLevel = state.Node.Level; + var to = new State( node, 0, 0 ); + var toLevel = node.Level; + + while( from.Node != to.Node ) + { + if( fromLevel > toLevel ) + { + if( !GeneratorNodeHelper.MoveToParent( ref from ) ) + return false; + + fromLevel = from.Node.Level; + } + else + { + if( !GeneratorNodeHelper.MoveToPrevious( ref to ) ) + { + if( !GeneratorNodeHelper.MoveToParent( ref to ) ) + return false; + + toLevel = to.Node.Level; + } + } + } + + state.Node = node; + state.Index = from.Index - to.Index; + state.DataIndex = from.DataIndex - to.DataIndex; + + return true; + } + + private static bool FindNodeForIndex( ref State state, int index ) + { + var current = state; + + // The algo is a single drill-down... for optimized performance.. + // It first tries to go horizontally in the tree and then drills-down if it can. + while( true ) + { + var itemCount = current.Node.ItemCount; + + // Verify if the current node contains ( directly or its children ) the required index + if( index < current.Index + itemCount ) + { + // A Group node is the only node that can have children is by definition empty... let's dig deeper. + // If we cannot travel deeper, then this node is the closest we get. + if( !GeneratorNodeHelper.MoveToChild( ref current ) ) + break; + } + else if( ( index == current.Index ) && ( itemCount != 0 ) ) + { + break; + } + else + { + if( !GeneratorNodeHelper.MoveToNext( ref current ) ) + return false; + } + } + + state.Node = current.Node; + state.Index = current.Index; + state.DataIndex = current.DataIndex; + + return true; + } + + private State m_state; + + #region State Private Struct + + private struct State + { + internal State( GeneratorNode node, int index, int dataIndex ) + { + Debug.Assert( node != null ); + + this.Node = node; + this.Index = index; + this.DataIndex = dataIndex; + } + + internal GeneratorNode Node; + internal int Index; + internal int DataIndex; + } + + #endregion } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GroupGeneratorNode.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GroupGeneratorNode.cs index 671e27f1..a0b3ce6a 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GroupGeneratorNode.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GroupGeneratorNode.cs @@ -32,15 +32,11 @@ namespace Xceed.Wpf.DataGrid m_groupConfig = groupConfig; } - #region PUBLIC EVENTS - public event EventHandler TotalLeafCountChanged; public event EventHandler IsExpandedChanged; public event EventHandler IsExpandedChanging; - #endregion PUBLIC EVENTS - - #region PUBLIC PROPERTIES + #region CollectionViewGroup Property public CollectionViewGroup CollectionViewGroup { @@ -50,6 +46,10 @@ namespace Xceed.Wpf.DataGrid } } + #endregion + + #region UIGroup Property + public Group UIGroup { get @@ -62,6 +62,10 @@ namespace Xceed.Wpf.DataGrid } } + #endregion + + #region GroupConfiguration Property + public GroupConfiguration GroupConfiguration { get @@ -70,6 +74,10 @@ namespace Xceed.Wpf.DataGrid } } + #endregion + + #region TotalLeafCount Property + public int TotalLeafCount { get @@ -78,6 +86,10 @@ namespace Xceed.Wpf.DataGrid } } + #endregion + + #region ItemCount Property + internal override int ItemCount { get @@ -91,6 +103,10 @@ namespace Xceed.Wpf.DataGrid } } + #endregion + + #region IsExpanded Property + public bool IsExpanded { get @@ -102,23 +118,59 @@ namespace Xceed.Wpf.DataGrid //if the expanded status changed if( m_isExpanded != value ) { - if( this.IsExpandedChanging != null ) + var dataGridContext = m_uiGroup.DataGridContext; + var groupExpansionChangingEventArgs = default( GroupExpansionChangingEventArgs ); + if( value ) + { + groupExpansionChangingEventArgs = new GroupExpansionChangingEventArgs( DataGridControl.GroupExpandingEvent, m_uiGroup, m_group, dataGridContext, true ); + dataGridContext.DataGridControl.RaiseGroupExpanding( groupExpansionChangingEventArgs ); + } + else + { + groupExpansionChangingEventArgs = new GroupExpansionChangingEventArgs( DataGridControl.GroupCollapsingEvent, m_uiGroup, m_group, dataGridContext, false ); + dataGridContext.DataGridControl.RaiseGroupCollapsing( groupExpansionChangingEventArgs ); + } + + if( groupExpansionChangingEventArgs.Cancel ) + return; + + var handler = this.IsExpandedChanging; + if( handler != null ) { - this.IsExpandedChanging( this, EventArgs.Empty ); + handler.Invoke( this, EventArgs.Empty ); } this.NotifyImmediateChildren( value ); m_isExpanded = value; - if( this.IsExpandedChanged != null ) + handler = this.IsExpandedChanged; + if( handler != null ) + { + handler.Invoke( this, EventArgs.Empty ); + } + + if( m_isExpanded ) + { + dataGridContext.DataGridControl.RaiseGroupExpanded( new GroupExpansionChangedEventArgs( DataGridControl.GroupExpandedEvent, m_uiGroup, m_group, dataGridContext, true ) ); + } + else { - this.IsExpandedChanged( this, EventArgs.Empty ); + dataGridContext.DataGridControl.RaiseGroupCollapsed( new GroupExpansionChangedEventArgs( DataGridControl.GroupCollapsedEvent, m_uiGroup, m_group, dataGridContext, false ) ); } } } } + internal void SetIsExpandedAtInitialization( bool isExpanded ) + { + m_isExpanded = isExpanded; + } + + #endregion + + #region NamesTree Property + public object[] NamesTree { get @@ -127,9 +179,29 @@ namespace Xceed.Wpf.DataGrid } } - #endregion PUBLIC PROPERTIES + #endregion + + #region Child Property + + public GeneratorNode Child + { + get; + set; + } + + #endregion - #region PUBLIC METHODS + #region IsComputedExpandedOverride Property + + protected override bool IsComputedExpandedOverride + { + get + { + return this.IsExpanded; + } + } + + #endregion public HeadersFootersGeneratorNode GetHeaderNode() { @@ -153,58 +225,6 @@ namespace Xceed.Wpf.DataGrid return footerGeneratorNode; } - internal override void NotifyExpansionStateChanged( bool isParentExpanded ) - { - base.NotifyExpansionStateChanged( isParentExpanded ); - - if( this.Parent != null ) - { - this.OnExpansionStateChanged( isParentExpanded, 0, m_itemCount ); - - if( isParentExpanded == true ) - { - this.Parent.AdjustItemCount( m_itemCount ); - } - else - { - this.Parent.AdjustItemCount( -m_itemCount ); - } - } - } - - internal override void CleanGeneratorNode() - { - base.CleanGeneratorNode(); - - this.Child = null; - this.UIGroup.ClearGroup(); - this.UIGroup = null; - - m_group = null; - } - - #endregion PUBLIC METHODS - - #region PUBLIC FIELDS - - public GeneratorNode Child; - - #endregion PUBLIC FIELDS - - #region PROTECTED PROPERTIES - - protected override bool IsComputedExpandedOverride - { - get - { - return this.IsExpanded; - } - } - - #endregion PROTECTED PROPERTIES - - #region PROTECTED METHODS - protected override int AdjustItemCountOverride( int delta ) { delta = base.AdjustItemCountOverride( delta ); @@ -237,9 +257,35 @@ namespace Xceed.Wpf.DataGrid return delta; } - #endregion PROTECTED METHODS + internal override void NotifyExpansionStateChanged( bool isParentExpanded ) + { + base.NotifyExpansionStateChanged( isParentExpanded ); + + if( this.Parent != null ) + { + this.OnExpansionStateChanged( isParentExpanded, 0, m_itemCount ); + + if( isParentExpanded == true ) + { + this.Parent.AdjustItemCount( m_itemCount ); + } + else + { + this.Parent.AdjustItemCount( -m_itemCount ); + } + } + } + + internal override void CleanGeneratorNode() + { + base.CleanGeneratorNode(); - #region INTERNAL METHODS + this.Child = null; + this.UIGroup.ClearGroup(); + this.UIGroup = null; + + m_group = null; + } internal void BuildNamesTree() { @@ -257,10 +303,6 @@ namespace Xceed.Wpf.DataGrid } } - #endregion INTERNAL METHODS - - #region PRIVATE METHODS - private void NotifyImmediateChildren( bool value ) { if( this.Child != null ) @@ -275,10 +317,6 @@ namespace Xceed.Wpf.DataGrid } } - #endregion PRIVATE METHODS - - #region PRIVATE FIELDS - private GroupConfiguration m_groupConfig; private bool m_isExpanded = true; private int m_leafCount; //this is the storage for the total number of "leaf" items that are child of this group. (no counting the groups, headers and footers) @@ -286,7 +324,5 @@ namespace Xceed.Wpf.DataGrid private CollectionViewGroup m_group; private Group m_uiGroup; private object[] m_namesTree; - - #endregion PRIVATE FIELDS } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GroupHeaderFooterItem.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GroupHeaderFooterItem.cs index cc840051..55f73cfb 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GroupHeaderFooterItem.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GroupHeaderFooterItem.cs @@ -15,26 +15,36 @@ ***********************************************************************************/ using System; +using System.Diagnostics; using System.Windows; using System.Windows.Data; -using Xceed.Wpf.DataGrid.Automation; namespace Xceed.Wpf.DataGrid { public struct GroupHeaderFooterItem { - #region CONSTRUCTORS + #region Static Fields + + public static readonly GroupHeaderFooterItem Empty = new GroupHeaderFooterItem(); + + #endregion public GroupHeaderFooterItem( CollectionViewGroup collectionViewGroup, object template ) { if( !( template is DataTemplate ) && !( template is GroupHeaderFooterItemTemplate ) ) throw new ArgumentException( "A GroupHeaderFooterItem can only be created with a DataTemplate or VisibleWhenCollapsed objects.", "template" ); + Debug.Assert( template != null ); + m_template = template; - m_weakGroup = new WeakReference( collectionViewGroup ); - } + m_group = new WeakReference( collectionViewGroup ); - #endregion CONSTRUCTORS + m_hashCode = template.GetHashCode(); + if( collectionViewGroup != null ) + { + m_hashCode ^= collectionViewGroup.GetHashCode(); + } + } #region Template Property @@ -46,9 +56,9 @@ namespace Xceed.Wpf.DataGrid } } - private object m_template; + private readonly object m_template; - #endregion Template Property + #endregion #region Group Property @@ -56,25 +66,22 @@ namespace Xceed.Wpf.DataGrid { get { - if( m_weakGroup.IsAlive ) - return m_weakGroup.Target as CollectionViewGroup; - - if( m_weakGroup.Target != null ) - m_weakGroup.Target = null; + if( m_group != null ) + return m_group.Target as CollectionViewGroup; return null; } } - private WeakReference m_weakGroup; - - #endregion Group Property + private readonly WeakReference m_group; - #region PUBLIC METHODS + #endregion public static bool Equals( GroupHeaderFooterItem item1, GroupHeaderFooterItem item2 ) { - return ( ( item1.m_template == item2.m_template ) && ( item1.Group == item2.Group ) ); + return ( item1.m_hashCode == item2.m_hashCode ) + && ( item1.m_template == item2.m_template ) + && ( item1.Group == item2.Group ); } public static bool operator ==( GroupHeaderFooterItem item1, GroupHeaderFooterItem item2 ) @@ -89,7 +96,7 @@ namespace Xceed.Wpf.DataGrid public override bool Equals( object obj ) { - if( ( obj == null ) || ( !( obj is GroupHeaderFooterItem ) ) ) + if( ( obj == null ) || !( obj is GroupHeaderFooterItem ) ) return false; return this.Equals( ( GroupHeaderFooterItem )obj ); @@ -102,21 +109,9 @@ namespace Xceed.Wpf.DataGrid public override int GetHashCode() { - int hashCode = 0; - - if( m_template != null ) - hashCode ^= m_template.GetHashCode(); - - CollectionViewGroup group = this.Group; - - if( group != null ) - hashCode ^= group.GetHashCode(); - - return hashCode; + return m_hashCode; } - #endregion PUBLIC METHODS - - public static readonly GroupHeaderFooterItem Empty = new GroupHeaderFooterItem(); + private readonly int m_hashCode; } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GroupHeaderFooterItemContainerRecyclingPool.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GroupHeaderFooterItemContainerRecyclingPool.cs new file mode 100644 index 00000000..18defb54 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/GroupHeaderFooterItemContainerRecyclingPool.cs @@ -0,0 +1,117 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal sealed class GroupHeaderFooterItemContainerRecyclingPool : IEnumerable + { + internal int Count + { + get + { + return m_count; + } + } + + internal void Clear() + { + m_collection.Clear(); + m_count = 0; + } + + internal void Enqueue( string groupBy, object template, DependencyObject container ) + { + if( groupBy == null ) + throw new ArgumentNullException( "groupBy" ); + + if( template == null ) + throw new ArgumentNullException( "template" ); + + var pool = default( HeaderFooterItemContainerRecyclingPool ); + if( m_collection.TryGetValue( groupBy, out pool ) ) + { + pool.Enqueue( template, container ); + } + else + { + pool = new HeaderFooterItemContainerRecyclingPool(); + pool.Enqueue( template, container ); + + m_collection.Add( groupBy, pool ); + } + + m_count++; + } + + internal DependencyObject Dequeue( string groupBy, object template ) + { + if( groupBy == null ) + throw new ArgumentNullException( "groupBy" ); + + if( template == null ) + throw new ArgumentNullException( "template" ); + + var pool = default( HeaderFooterItemContainerRecyclingPool ); + if( !m_collection.TryGetValue( groupBy, out pool ) ) + return null; + + var container = pool.Dequeue( template ); + if( container != null ) + { + if( pool.Count == 0 ) + { + m_collection.Remove( groupBy ); + } + + m_count--; + } + + return container; + } + + #region IEnumerable<> Members + + public IEnumerator GetEnumerator() + { + foreach( var pool in m_collection.Values ) + { + foreach( var entry in pool ) + { + yield return entry; + } + } + } + + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + #endregion + + private int m_count; //0 + private readonly Dictionary m_collection = new Dictionary(); + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/HeaderFooterItemContainerRecyclingPool.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/HeaderFooterItemContainerRecyclingPool.cs new file mode 100644 index 00000000..0968de47 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/HeaderFooterItemContainerRecyclingPool.cs @@ -0,0 +1,190 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal sealed class HeaderFooterItemContainerRecyclingPool : IEnumerable + { + internal int Count + { + get + { + return m_count; + } + } + + internal void Clear() + { + if( m_count <= 0 ) + return; + + m_collection.Clear(); + m_count = 0; + m_version++; + } + + internal void Enqueue( object item, DependencyObject container ) + { + if( item == null ) + throw new ArgumentNullException( "item" ); + + if( container == null ) + throw new ArgumentNullException( "container" ); + + var entry = default( Entry ); + + if( !m_collection.TryGetValue( item, out entry ) ) + { + entry = new Entry(); + } + + entry.Push( container ); + + m_collection[ item ] = entry; + m_count++; + m_version++; + } + + internal DependencyObject Dequeue( object item ) + { + if( item == null ) + throw new ArgumentNullException( "item" ); + + if( m_collection.Count <= 0 ) + return null; + + var entry = default( Entry ); + + if( !m_collection.TryGetValue( item, out entry ) ) + return null; + + Debug.Assert( entry.Count > 0 ); + var container = entry.Pop(); + Debug.Assert( container != null ); + + if( entry.Count == 0 ) + { + m_collection.Remove( item ); + } + else + { + m_collection[ item ] = entry; + } + + m_count--; + m_version++; + + return container; + } + + #region IEnumerable<> Members + + public IEnumerator GetEnumerator() + { + var version = m_version; + + foreach( var entry in m_collection.Values ) + { + for( int i = entry.Count - 1; i >= 0; i-- ) + { + if( version != m_version ) + throw new InvalidOperationException(); + + yield return entry[ i ]; + } + } + } + + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + #endregion + + private int m_count; //0 + private int m_version; //0 + private readonly Dictionary m_collection = new Dictionary(); + + #region Entry Private Struct + + private struct Entry + { + internal int Count + { + get + { + return m_count; + } + } + + internal DependencyObject this[ int index ] + { + get + { + Debug.Assert( ( index >= 0 ) && ( index < m_count ) ); + return m_containers[ index ]; + } + } + + internal void Push( DependencyObject container ) + { + Debug.Assert( container != null ); + + if( m_containers == null ) + { + Array.Resize( ref m_containers, 1 ); + } + else if( m_count == m_containers.Length ) + { + Debug.Assert( m_containers.Length > 0 ); + Array.Resize( ref m_containers, m_containers.Length * 2 ); + } + + m_containers[ m_count ] = container; + m_count++; + } + + internal DependencyObject Pop() + { + Debug.Assert( m_count > 0 ); + Debug.Assert( m_containers != null ); + + m_count--; + + var container = m_containers[ m_count ]; + m_containers[ m_count ] = default( DependencyObject ); + + return container; + } + + private int m_count; //0 + private DependencyObject[] m_containers; //null + } + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/HeadersFootersGeneratorNode.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/HeadersFootersGeneratorNode.cs index d3a0131d..91849d2c 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/HeadersFootersGeneratorNode.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/HeadersFootersGeneratorNode.cs @@ -86,7 +86,7 @@ namespace Xceed.Wpf.DataGrid for( int i = 0; i < this.Items.Count; i++ ) { //determine if the DataTemplate for the node is a GroupHeaderFooterTemplate - groupHeaderTemplate = this.Items[ i ] as GroupHeaderFooterItemTemplate; + groupHeaderTemplate = this.Items[ i ] as GroupHeaderFooterItemTemplate; //if the Node represent a GroupHeader of GroupFooter and the template is a GroupHeaderFooterTemplate which //is VisibleWhenCollapsed @@ -180,36 +180,35 @@ namespace Xceed.Wpf.DataGrid public override object GetAt( int index ) { - object retval = null; - GroupGeneratorNode parentGroup = this.Parent as GroupGeneratorNode; - if( ( parentGroup != null ) && ( parentGroup.IsExpanded == false ) ) + var parentGroup = this.Parent as GroupGeneratorNode; + object item; + + if( ( parentGroup != null ) && !parentGroup.IsExpanded ) { - retval = this.ComputeCollapsedGetAt( index ); + item = this.ComputeCollapsedGetAt( index ); } else { - retval = base.GetAt( index ); + item = base.GetAt( index ); } - if( parentGroup != null ) - { - retval = new GroupHeaderFooterItem( parentGroup.CollectionViewGroup, retval ); - } + if( ( parentGroup != null ) && ( item != null ) ) + return new GroupHeaderFooterItem( parentGroup.CollectionViewGroup, item ); - return retval; + return item; } #region ImmediateUIGroups internal ReadOnlyCollection GetImmediateUIGroups( int generatorCurrentGeneration ) { - if( ( m_cachedGeneratorCurrentGeneration != generatorCurrentGeneration ) + if( ( m_cachedGeneratorCurrentGeneration != generatorCurrentGeneration ) || ( m_readOnlyImmediateUIGroups == null ) ) { Debug.WriteLineIf( ( ( m_cachedGeneratorCurrentGeneration != generatorCurrentGeneration ) && ( m_readOnlyImmediateUIGroups == null ) ), "Creating Groups collection since generator version differs AND ReadOnlyCollection is null." ); - Debug.WriteLineIf( ( ( m_cachedGeneratorCurrentGeneration != generatorCurrentGeneration ) && ( m_readOnlyImmediateUIGroups != null ) ), + Debug.WriteLineIf( ( ( m_cachedGeneratorCurrentGeneration != generatorCurrentGeneration ) && ( m_readOnlyImmediateUIGroups != null ) ), "Creating Groups collection since generator version differs." ); Debug.WriteLineIf( ( ( m_cachedGeneratorCurrentGeneration == generatorCurrentGeneration ) && ( m_readOnlyImmediateUIGroups == null ) ), diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ICustomItemContainerGenerator.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ICustomItemContainerGenerator.cs index 3fdf6072..60a172bd 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ICustomItemContainerGenerator.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ICustomItemContainerGenerator.cs @@ -14,8 +14,8 @@ ***********************************************************************************/ -using System.Windows.Controls.Primitives; using System.Windows; +using System.Windows.Controls.Primitives; namespace Xceed.Wpf.DataGrid { @@ -37,7 +37,7 @@ namespace Xceed.Wpf.DataGrid int GetRealizedIndexForContainer( DependencyObject container ); void SetCurrentIndex( int newCurrentIndex ); - int GetCurrentIndex( ); + int GetCurrentIndex(); void RestoreFocus( DependencyObject container ); } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ItemContainerRecyclingPool.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ItemContainerRecyclingPool.cs new file mode 100644 index 00000000..0d40ba07 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ItemContainerRecyclingPool.cs @@ -0,0 +1,192 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal sealed class ItemContainerRecyclingPool : IEnumerable + { + internal int Count + { + get + { + return m_count; + } + } + + internal void Clear() + { + if( m_count <= 0 ) + return; + + m_collection.Clear(); + m_count = 0; + m_version++; + } + + internal void Enqueue( object hint, DependencyObject container ) + { + if( container == null ) + throw new ArgumentNullException( "container" ); + + var key = ( hint != null ) ? hint.GetHashCode() : 0; + var entry = default( Entry ); + + if( !m_collection.TryGetValue( key, out entry ) ) + { + entry = new Entry(); + } + + entry.Push( container ); + + m_collection[ key ] = entry; + m_count++; + m_version++; + } + + internal DependencyObject Dequeue( object hint ) + { + if( m_collection.Count <= 0 ) + return null; + + var key = ( hint != null ) ? hint.GetHashCode() : 0; + var entry = default( Entry ); + + if( !m_collection.TryGetValue( key, out entry ) ) + { + var pair = m_collection.First(); + + key = pair.Key; + entry = pair.Value; + } + + Debug.Assert( entry.Count > 0 ); + var container = entry.Pop(); + Debug.Assert( container != null ); + + if( entry.Count == 0 ) + { + m_collection.Remove( key ); + } + else + { + m_collection[ key ] = entry; + } + + m_count--; + m_version++; + + return container; + } + + #region IEnumerable<> Members + + public IEnumerator GetEnumerator() + { + var version = m_version; + + foreach( var entry in m_collection.Values ) + { + for( int i = entry.Count - 1; i >= 0; i-- ) + { + if( version != m_version ) + throw new InvalidOperationException(); + + yield return entry[ i ]; + } + } + } + + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + #endregion + + private int m_count; //0 + private int m_version; //0 + private readonly Dictionary m_collection = new Dictionary(); + + #region Entry Private Struct + + private struct Entry + { + internal int Count + { + get + { + return m_count; + } + } + + internal DependencyObject this[ int index ] + { + get + { + Debug.Assert( ( index >= 0 ) && ( index < m_count ) ); + return m_containers[ index ]; + } + } + + internal void Push( DependencyObject container ) + { + Debug.Assert( container != null ); + + if( m_containers == null ) + { + Array.Resize( ref m_containers, 1 ); + } + else if( m_count == m_containers.Length ) + { + Debug.Assert( m_containers.Length > 0 ); + Array.Resize( ref m_containers, m_containers.Length * 2 ); + } + + m_containers[ m_count ] = container; + m_count++; + } + + internal DependencyObject Pop() + { + Debug.Assert( m_count > 0 ); + Debug.Assert( m_containers != null ); + + m_count--; + + var container = m_containers[ m_count ]; + m_containers[ m_count ] = default( DependencyObject ); + + return container; + } + + private int m_count; //0 + private DependencyObject[] m_containers; //null + } + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ItemContextVisitor.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ItemContextVisitor.cs index 5986ac07..ebd0e1c8 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ItemContextVisitor.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ItemContextVisitor.cs @@ -15,23 +15,22 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Text; using System.Windows; +using System.Windows.Data; +using Xceed.Wpf.DataGrid.Views; namespace Xceed.Wpf.DataGrid { - internal class ItemContextVisitor : IDataGridContextVisitor + internal sealed class ItemContextVisitor : IDataGridContextVisitor { - public ItemContextVisitor( bool isTableFlowView ) + internal ItemContextVisitor( TableflowViewItemsHost itemsHost, double firstItemHiddenRatio ) { - m_isTableFlowView = isTableFlowView; + m_itemsHost = itemsHost; + m_firstItemHiddenRatio = firstItemHiddenRatio; } #region ParentDataGridContext - private DataGridContext m_parentDataGridContext; - public DataGridContext ParentDataGridContext { get @@ -40,11 +39,11 @@ namespace Xceed.Wpf.DataGrid } } - #endregion ParentDataGridContext + private DataGridContext m_parentDataGridContext; - #region Item Property + #endregion - private object m_item; + #region Item Property public object Item { @@ -54,7 +53,9 @@ namespace Xceed.Wpf.DataGrid } } - #endregion Item Property + private object m_item; + + #endregion #region VisitSuccessful Property @@ -84,39 +85,46 @@ namespace Xceed.Wpf.DataGrid public void Visit( DataGridContext sourceContext, int sourceDataItemIndex, object item, ref bool stopVisit ) { - if( !m_isTableFlowView ) + // In TableflowView, we must consider that sticky headers may hide the item. + if( m_itemsHost != null ) { - m_item = item; - m_parentDataGridContext = sourceContext; - m_success = true; - stopVisit = true; - return; - } - - UIElement dataRow = sourceContext.CustomItemContainerGenerator.ContainerFromItem( item ) as UIElement; - - if( dataRow != null ) - { - if( !ScrollTip.IsItemInView( dataRow, sourceContext.DataGridControl.ItemsHost ) ) + if( m_isFirstItem ) { - stopVisit = true; + m_isFirstItem = false; + + // At least half the item is hidden. + if( m_firstItemHiddenRatio > 0.5d ) + return; } - else if( !ScrollTip.IsDataItemHiddenBySticky( sourceContext, item ) ) + + var areHeadersSticky = TableflowView.GetAreHeadersSticky( sourceContext ); + var areGroupHeadersSticky = TableflowView.GetAreGroupHeadersSticky( sourceContext ); + var areParentRowsSticky = TableflowView.GetAreParentRowsSticky( sourceContext ); + + if( areHeadersSticky || areGroupHeadersSticky || areParentRowsSticky ) { - m_item = item; - m_parentDataGridContext = sourceContext; - m_success = true; - stopVisit = true; + var stickyHeadersCount = sourceContext.CustomItemContainerGenerator.GetStickyHeaderCountForIndex( sourceDataItemIndex, areHeadersSticky, areGroupHeadersSticky, areParentRowsSticky ); + + if( stickyHeadersCount > m_stickyHeadersSkipped ) + { + m_stickyHeadersSkipped++; + return; + } } } + + m_item = item; + m_parentDataGridContext = sourceContext; + m_success = true; + stopVisit = true; } - public void Visit( DataGridContext sourceContext, System.Windows.Data.CollectionViewGroup group, object[] namesTree, int groupLevel, bool isExpanded, bool isComputedExpanded, ref bool stopVisit ) + public void Visit( DataGridContext sourceContext, CollectionViewGroup group, object[] namesTree, int groupLevel, bool isExpanded, bool isComputedExpanded, ref bool stopVisit ) { throw new NotSupportedException( "The ItemAndDataGridContextVisitor is only capable of handling data items." ); } - public void Visit( DataGridContext sourceContext, System.Windows.DataTemplate headerFooter, ref bool stopVisit ) + public void Visit( DataGridContext sourceContext, DataTemplate headerFooter, ref bool stopVisit ) { throw new NotSupportedException( "The ItemAndDataGridContextVisitor is only capable of handling data items." ); } @@ -128,6 +136,9 @@ namespace Xceed.Wpf.DataGrid #endregion - private bool m_isTableFlowView; + private readonly TableflowViewItemsHost m_itemsHost; + private readonly double m_firstItemHiddenRatio; + private bool m_isFirstItem = true; + private int m_stickyHeadersSkipped; //0 } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ItemsGeneratorNode.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ItemsGeneratorNode.cs index 8431c83f..5a107b4f 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ItemsGeneratorNode.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/ItemsGeneratorNode.cs @@ -16,36 +16,25 @@ using System.Collections; using System.Collections.Generic; -using System.Collections.Specialized; namespace Xceed.Wpf.DataGrid { internal partial class ItemsGeneratorNode : CollectionGeneratorNode { - public ItemsGeneratorNode( IList list, GeneratorNode parent ) + internal ItemsGeneratorNode( IList list, GeneratorNode parent ) : base( list, parent ) { - } internal override int ItemCount { get { - GroupGeneratorNode parentGroup = this.Parent as GroupGeneratorNode; - if( parentGroup != null ) - { - int totalItemCount = 0; - - if( parentGroup.IsExpanded == true ) - { - totalItemCount = this.Items.Count + this.ComputeDetailsCount(); - } + var parentGroup = this.Parent as GroupGeneratorNode; + if( ( parentGroup == null ) || parentGroup.IsExpanded ) + return this.Items.Count + this.ComputeDetailsCount(); - return totalItemCount; - } - - return this.Items.Count + this.ComputeDetailsCount(); + return 0; } } @@ -57,7 +46,7 @@ namespace Xceed.Wpf.DataGrid { this.OnExpansionStateChanged( isParentExpanded, 0, this.Items.Count + this.ComputeDetailsCount() ); - if( isParentExpanded == true ) + if( isParentExpanded ) { this.Parent.AdjustItemCount( this.Items.Count + this.ComputeDetailsCount() ); } @@ -72,13 +61,11 @@ namespace Xceed.Wpf.DataGrid { base.AdjustItemCountOverride( delta ); - GroupGeneratorNode parentGroup = this.Parent as GroupGeneratorNode; - if( ( parentGroup != null ) && ( parentGroup.IsExpanded == false ) ) - { - return 0; - } + var parentGroup = this.Parent as GroupGeneratorNode; + if( ( parentGroup == null ) || parentGroup.IsExpanded ) + return delta; - return delta; + return 0; } public override object GetAt( int index ) @@ -86,59 +73,48 @@ namespace Xceed.Wpf.DataGrid if( index < 0 ) return null; - if( ( m_detailsMapping == null ) - || ( m_detailsMapping.Count == 0 ) ) - { - //If there are no details, call base (quicker) + //If there are no details, call base (quicker) + if( ( m_detailsMapping == null ) || ( m_detailsMapping.Count == 0 ) ) return base.GetAt( index ); - } int masterIndex; int detailIndex; int detailNodeIndex; - DetailGeneratorNode detailNode = this.GetDetailNodeForIndex( index, out masterIndex, out detailIndex, out detailNodeIndex ); + var detailNode = this.GetDetailNodeForIndex( index, out masterIndex, out detailIndex, out detailNodeIndex ); if( detailNode == null ) - { return this.Items[ masterIndex ]; - } return detailNode.DetailGenerator.ItemFromIndex( detailIndex ); } public override int IndexOf( object item ) { - if( ( m_detailsMapping == null ) - || ( m_detailsMapping.Count == 0 ) ) - { + if( ( m_detailsMapping == null ) || ( m_detailsMapping.Count == 0 ) ) return base.IndexOf( item ); - } - int tmpIndex = this.Items.IndexOf( item ); - if( tmpIndex != -1 ) - { + var tmpIndex = this.Items.IndexOf( item ); + if( tmpIndex >= 0 ) return tmpIndex + this.CountDetailsBeforeDataIndex( tmpIndex ); - } int runningDetailCount = 0; foreach( KeyValuePair> pair in m_detailsMapping ) { - List detailNodeList = pair.Value; - - int currentIndex = pair.Key; - int runningIndex = ( currentIndex + runningDetailCount ); + var detailNodeList = pair.Value; + var currentIndex = pair.Key; + var runningIndex = ( currentIndex + runningDetailCount ); - int count = detailNodeList.Count; + var count = detailNodeList.Count; for( int i = 0; i < count; i++ ) { - DetailGeneratorNode detailNode = detailNodeList[ i ]; - int detailIndex = detailNode.DetailGenerator.IndexFromItem( item ); + var detailNode = detailNodeList[ i ]; + var detailIndex = detailNode.DetailGenerator.IndexFromItem( item ); - if( detailIndex > -1 ) + if( detailIndex >= 0 ) return runningIndex + detailIndex + 1; - int detailItemCount = detailNode.ItemCount; + var detailItemCount = detailNode.ItemCount; runningDetailCount += detailItemCount; runningIndex += detailItemCount; @@ -154,10 +130,11 @@ namespace Xceed.Wpf.DataGrid if( m_detailsMapping != null ) { - foreach( List detail in m_detailsMapping.Values ) + foreach( var detail in m_detailsMapping.Values ) { detail.Clear(); } + m_detailsMapping.Clear(); m_detailsMapping = null; } @@ -179,34 +156,36 @@ namespace Xceed.Wpf.DataGrid private int ComputeDetailsCount() { - int retval = 0; - if( m_detailsMapping != null ) + if( m_detailsMapping == null ) + return 0; + + var count = 0; + + foreach( var detailsList in m_detailsMapping.Values ) { - foreach( List detailsList in m_detailsMapping.Values ) + foreach( var detail in detailsList ) { - foreach( DetailGeneratorNode detail in detailsList ) - { - retval += detail.ItemCount; - } + count += detail.ItemCount; } } - return retval; + + return count; } internal int CountDetailsBeforeDataIndex( int dataIndex ) { - if( this.Details == null ) + if( m_detailsMapping == null ) return 0; - int retval = 0; + var count = 0; foreach( KeyValuePair> indexToDetails in m_detailsMapping ) { if( indexToDetails.Key < dataIndex ) { - foreach( DetailGeneratorNode node in indexToDetails.Value ) + foreach( var node in indexToDetails.Value ) { - retval += node.ItemCount; + count += node.ItemCount; } continue; @@ -218,7 +197,7 @@ namespace Xceed.Wpf.DataGrid break; } - return retval; + return count; } internal int CountDetailsBeforeGlobalIndex( int globalIndex ) @@ -226,11 +205,11 @@ namespace Xceed.Wpf.DataGrid if( ( m_detailsMapping == null ) || ( globalIndex == 0 ) ) return 0; - int retval = 0; + var retval = 0; foreach( KeyValuePair> indexToDetails in m_detailsMapping ) { - int key = indexToDetails.Key; + var key = indexToDetails.Key; // Since the details list is now a SortedDictionary, we can assume // that if the key is greater or equal than the reference index, @@ -238,9 +217,9 @@ namespace Xceed.Wpf.DataGrid if( key >= globalIndex ) break; - foreach( DetailGeneratorNode node in indexToDetails.Value ) + foreach( var node in indexToDetails.Value ) { - int itemCount = node.ItemCount; + var itemCount = node.ItemCount; globalIndex -= itemCount; if( key >= globalIndex ) @@ -255,9 +234,10 @@ namespace Xceed.Wpf.DataGrid public DetailGeneratorNode GetDetailNodeForIndex( int targetIndex ) { - int masterIndex = -1; - int detailIndex = -1; - int detailNodeIndex = -1; + int masterIndex; + int detailIndex; + int detailNodeIndex; + return this.GetDetailNodeForIndex( targetIndex, out masterIndex, out detailIndex, out detailNodeIndex ); } @@ -267,21 +247,19 @@ namespace Xceed.Wpf.DataGrid detailIndex = -1; detailNodeIndex = -1; - if( ( m_detailsMapping == null ) - || ( m_detailsMapping.Count == 0 ) ) + if( ( m_detailsMapping == null ) || ( m_detailsMapping.Count == 0 ) ) { masterIndex = targetIndex; return null; } - int runningDetailCount = 0; + var runningDetailCount = 0; foreach( KeyValuePair> pair in m_detailsMapping ) { - List detailNodeList = pair.Value; - int currentIndex = pair.Key; - - int runningIndex = ( currentIndex + runningDetailCount ); + var detailNodeList = pair.Value; + var currentIndex = pair.Key; + var runningIndex = ( currentIndex + runningDetailCount ); if( targetIndex < runningIndex ) { @@ -295,11 +273,11 @@ namespace Xceed.Wpf.DataGrid return null; } - int count = detailNodeList.Count; + var count = detailNodeList.Count; for( int i = 0; i < count; i++ ) { - DetailGeneratorNode detailNode = detailNodeList[ i ]; - int detailItemCount = detailNode.ItemCount; + var detailNode = detailNodeList[ i ]; + var detailItemCount = detailNode.ItemCount; if( targetIndex <= ( runningIndex + detailItemCount ) ) { diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/NamesTreeGroupFinderVisitor.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/NamesTreeGroupFinderVisitor.cs deleted file mode 100644 index 1b477e4d..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/NamesTreeGroupFinderVisitor.cs +++ /dev/null @@ -1,91 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Data; - -namespace Xceed.Wpf.DataGrid -{ - internal class NamesTreeGroupFinderVisitor : IDataGridContextVisitor - { - public NamesTreeGroupFinderVisitor( object[] namesTree ) - { - if( namesTree == null ) - throw new ArgumentNullException( "namesTree" ); - - if( namesTree.Length == 0 ) - throw new ArgumentException( "namesTree should not be an empty array", "namesTree" ); - - m_groupNamesTreeKey = new GroupNamesTreeKey( namesTree ); - } - - #region CollectionViewGroup Group - - public CollectionViewGroup Group - { - get; - private set; - } - - #endregion - - #region IDataGridContextVisitor Members - - public void Visit( DataGridContext sourceContext, System.Windows.Data.CollectionViewGroup group, object[] namesTree, int groupLevel, bool isExpanded, bool isComputedExpanded, ref bool stopVisit ) - { - if( this.Group == null ) - { - GroupNamesTreeKey currentGroupKey = new GroupNamesTreeKey( namesTree ); - - if( currentGroupKey.Equals( m_groupNamesTreeKey ) == true ) - this.Group = group; - - } - } - - public void Visit( DataGridContext sourceContext, ref bool stopVisit ) - { - throw new NotSupportedException(); - } - - public void Visit( DataGridContext sourceContext, int startSourceDataItemIndex, int endSourceDataItemIndex, ref bool stopVisit ) - { - throw new NotSupportedException(); - } - - public void Visit( DataGridContext sourceContext, int sourceDataItemIndex, object item, ref bool stopVisit ) - { - throw new NotSupportedException(); - } - - public void Visit( DataGridContext sourceContext, System.Windows.DataTemplate headerFooter, ref bool stopVisit ) - { - throw new NotSupportedException(); - } - - public void Visit( DataGridContext sourceContext, GroupHeaderFooterItem groupHeaderFooter, ref bool stopVisit ) - { - throw new NotSupportedException(); - } - - #endregion - - private GroupNamesTreeKey m_groupNamesTreeKey; - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/NotifyCollectionChangedGeneratorNode.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/NotifyCollectionChangedGeneratorNode.cs index 11f005bb..c6e09415 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/NotifyCollectionChangedGeneratorNode.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/NotifyCollectionChangedGeneratorNode.cs @@ -15,7 +15,6 @@ ***********************************************************************************/ using System.Collections.Specialized; -using System.ComponentModel; namespace Xceed.Wpf.DataGrid { @@ -30,10 +29,11 @@ namespace Xceed.Wpf.DataGrid public void OnCollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) { - if( this.CollectionChanged != null ) - { - this.CollectionChanged( this, e ); - } + var handler = this.CollectionChanged; + if( handler == null ) + return; + + handler.Invoke( this, e ); } } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/RangeSelectionVisitor.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/RangeSelectionVisitor.cs index 175a11b8..aab7e77d 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/RangeSelectionVisitor.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/RangeSelectionVisitor.cs @@ -57,11 +57,6 @@ namespace Xceed.Wpf.DataGrid if( intersectionSelectionRange.IsEmpty ) continue; -#if DEBUG - string action = ( m_unselect ) ? "Removing" : "Adding"; - Debug.WriteLine( "Selection : " + action + " cell : (" + startSourceDataItemIndex.ToString() + " - " + endSourceDataItemIndex.ToString() + ") - (" - + intersectionSelectionRange.StartIndex.ToString() + " - " + intersectionSelectionRange.EndIndex.ToString() + ")" ); -#endif var cellRange = new SelectionCellRangeWithItems( new SelectionRange( startSourceDataItemIndex, endSourceDataItemIndex ), null, intersectionSelectionRange ); @@ -77,10 +72,6 @@ namespace Xceed.Wpf.DataGrid } else { -#if DEBUG - string action = ( m_unselect ) ? "Removing" : "Adding"; - Debug.WriteLine( "Selection : " + action + " Adding item : " + startSourceDataItemIndex.ToString() + " - " + endSourceDataItemIndex.ToString() ); -#endif var itemRange = new SelectionRangeWithItems( new SelectionRange( startSourceDataItemIndex, endSourceDataItemIndex ), null ); if( m_unselect ) diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/RecyclingCandidateCleanedEvent.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/RecyclingCandidateCleanedEvent.cs new file mode 100644 index 00000000..6c4beb1d --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/RecyclingCandidateCleanedEvent.cs @@ -0,0 +1,46 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal delegate void RecyclingCandidatesCleanedEventHandler( object sender, RecyclingCandidatesCleanedEventArgs e ); + + internal class RecyclingCandidatesCleanedEventArgs : EventArgs + { + public RecyclingCandidatesCleanedEventArgs( IList recyclingCandidates ) + { + if( recyclingCandidates == null ) + throw new ArgumentNullException( "recyclingCandidates" ); + + m_recyclingCandidates = recyclingCandidates; + } + + public IList RecyclingCandidates + { + get + { + return m_recyclingCandidates; + } + } + + private IList m_recyclingCandidates; + } + +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/SaveRestoreDataGridContextStateVisitor.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/SaveRestoreDataGridContextStateVisitor.cs index 8ab24f65..7c385052 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/SaveRestoreDataGridContextStateVisitor.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/SaveRestoreDataGridContextStateVisitor.cs @@ -129,36 +129,24 @@ namespace Xceed.Wpf.DataGrid { for( int i = 0; i < m_itemsToExpand.Count; i++ ) { - object dataItemToExpand = m_itemsToExpand[ i ].Target; + var dataItemToExpand = m_itemsToExpand[ i ].Target; + if( dataItemToExpand == null ) + continue; - if( dataItemToExpand != null ) + // Verify if we have a System.Data.DataView as ItemsSource to + // ensure to restore the System.Data.DataRowView that represents + // the System.Data.DataRow saved previously + System.Data.DataView dataView = ItemsSourceHelper.TryGetDataViewFromDataGridContext( m_rootDataGridContext ); + + if( ( dataView != null ) && ( dataItemToExpand is System.Data.DataRow ) ) { - try + foreach( System.Data.DataRowView dataRowView in dataView ) { - // Verify if we have a System.Data.DataView as ItemsSource to - // ensure to restore the System.Data.DataRowView that represents - // the System.Data.DataRow saved previously - System.Data.DataView dataView = - ItemsSourceHelper.TryGetDataViewFromDataGridContext( m_rootDataGridContext ); - - if( ( dataView != null ) - && ( dataItemToExpand is System.Data.DataRow ) ) + if( dataRowView.Row == dataItemToExpand ) { - foreach( System.Data.DataRowView dataRowView in dataView ) - { - if( dataRowView.Row == dataItemToExpand ) - { - dataItemToExpand = dataRowView; - break; - } - } + dataItemToExpand = dataRowView; + break; } - - m_rootDataGridContext.ExpandDetails( dataItemToExpand ); - } - catch - { - System.Diagnostics.Debug.Assert( false, "Item has moved in the source ?" ); } } } @@ -218,16 +206,16 @@ namespace Xceed.Wpf.DataGrid { if( wasExpanded ) { - sourceContext.ExpandGroupCore( group, true ); + sourceContext.ExpandGroup( group, true ); } else { - sourceContext.CollapseGroupCore( group, true ); + sourceContext.CollapseGroup( group, true ); } } else if( m_stopAtFirstCollapsedGroup ) { - sourceContext.CollapseGroupCore( group, true ); + sourceContext.CollapseGroup( group, true ); } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/SaveRestoreGlobalStateVisitor.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/SaveRestoreGlobalStateVisitor.cs index 727a9316..edb805a2 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/SaveRestoreGlobalStateVisitor.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/SaveRestoreGlobalStateVisitor.cs @@ -14,36 +14,34 @@ ***********************************************************************************/ -using System; using System.Collections.Generic; -using System.Text; namespace Xceed.Wpf.DataGrid { internal class SaveRestoreGlobalStateVisitor : SaveRestoreStateVisitor { - #region CONSTRUCTORS - - public SaveRestoreGlobalStateVisitor( bool stopAtFirstCollapsedGroup ) + internal SaveRestoreGlobalStateVisitor( bool stopAtFirstCollapsedGroup ) { m_stopAtFirstCollapsedGroup = stopAtFirstCollapsedGroup; } - #endregion CONSTRUCTORS - - #region StopAtFirstCollapsedGroup PROPERTY - - private bool m_stopAtFirstCollapsedGroup; + #region StopAtFirstCollapsedGroup Property - public bool StopAtFirstCollapsedGroup + internal bool StopAtFirstCollapsedGroup { - get { return m_stopAtFirstCollapsedGroup; } - set { m_stopAtFirstCollapsedGroup = value; } + get + { + return m_stopAtFirstCollapsedGroup; + } + set + { + m_stopAtFirstCollapsedGroup = value; + } } - #endregion StopAtFirstCollapsedGroup PROPERTY + private bool m_stopAtFirstCollapsedGroup; - #region PROTECTED METHODS + #endregion protected override void InitializeCore() { @@ -52,34 +50,27 @@ namespace Xceed.Wpf.DataGrid protected override void SaveStateCore( IDataGridContextVisitable dataGridContextVisitable ) { - DataGridContext rootDataGridContext = SaveRestoreStateVisitor.GetDataGridContextFromVisitable( dataGridContextVisitable ); + var dataGridContext = SaveRestoreStateVisitor.GetDataGridContextFromVisitable( dataGridContextVisitable ); - this.RecursiveSaveDataGridContextsState( rootDataGridContext ); + this.RecursiveSaveDataGridContextsState( dataGridContext ); } protected override void RestoreStateCore( IDataGridContextVisitable dataGridContextVisitable ) { - DataGridContext rootDataGridContext = SaveRestoreStateVisitor.GetDataGridContextFromVisitable( dataGridContextVisitable ); + var dataGridContext = SaveRestoreStateVisitor.GetDataGridContextFromVisitable( dataGridContextVisitable ); - this.RecursiveRestoreDataGridContextsState( rootDataGridContext ); + this.RecursiveRestoreDataGridContextsState( dataGridContext ); } - #endregion PROTECTED METHODS - - #region PRIVATE METHODS - private void RecursiveSaveDataGridContextsState( DataGridContext dataGridContext ) { - SaveRestoreDataGridContextStateVisitor saveRestoreDataGridContextStateVisitor - = new SaveRestoreDataGridContextStateVisitor( true, int.MaxValue, m_stopAtFirstCollapsedGroup ); + var saveRestoreDataGridContextStateVisitor = new SaveRestoreDataGridContextStateVisitor( true, int.MaxValue, m_stopAtFirstCollapsedGroup ); saveRestoreDataGridContextStateVisitor.SaveState( dataGridContext as IDataGridContextVisitable ); m_dataGridContextsStateDictionary.Add( new WeakDataGridContextKey( dataGridContext ), saveRestoreDataGridContextStateVisitor ); - IEnumerable subDataGridContexts = dataGridContext.GetChildContexts(); - - foreach( DataGridContext subDataGridContext in subDataGridContexts ) + foreach( var subDataGridContext in dataGridContext.GetChildContextsCore() ) { this.RecursiveSaveDataGridContextsState( subDataGridContext ); } @@ -87,9 +78,8 @@ namespace Xceed.Wpf.DataGrid private void RecursiveRestoreDataGridContextsState( DataGridContext dataGridContext ) { - WeakDataGridContextKey weakDataGridContextKey = new WeakDataGridContextKey( dataGridContext ); - - SaveRestoreDataGridContextStateVisitor saveRestoreDataGridContextStateVisitor; + var weakDataGridContextKey = new WeakDataGridContextKey( dataGridContext ); + var saveRestoreDataGridContextStateVisitor = default( SaveRestoreDataGridContextStateVisitor ); if( m_dataGridContextsStateDictionary.TryGetValue( weakDataGridContextKey, out saveRestoreDataGridContextStateVisitor ) ) { @@ -103,19 +93,12 @@ namespace Xceed.Wpf.DataGrid } } - IEnumerable subDataGridContexts = dataGridContext.GetChildContexts(); - foreach( DataGridContext subDataGridContext in subDataGridContexts ) + foreach( var subDataGridContext in dataGridContext.GetChildContextsCore() ) { this.RecursiveRestoreDataGridContextsState( subDataGridContext ); } } - #endregion PRIVATE METHODS - - #region PRIVATE FIELDS - - Dictionary m_dataGridContextsStateDictionary; - - #endregion PRIVATE FIELDS + private Dictionary m_dataGridContextsStateDictionary; } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/VisibilityChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/VisibilityChangedEventManager.cs deleted file mode 100644 index 493ea869..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/VisibilityChangedEventManager.cs +++ /dev/null @@ -1,74 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class VisibilityChangedEventManager : WeakEventManager - { - private VisibilityChangedEventManager() - { - } - - public static void AddListener( ColumnCollection source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( ColumnCollection source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - var columnCollection = ( ColumnCollection )source; - columnCollection.ColumnVisibilityChanged += new EventHandler( this.OnColumnVisibilityChanged ); - } - - protected override void StopListening( object source ) - { - var columnCollection = ( ColumnCollection )source; - columnCollection.ColumnVisibilityChanged -= new EventHandler( this.OnColumnVisibilityChanged ); - } - - private static VisibilityChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( VisibilityChangedEventManager ); - VisibilityChangedEventManager currentManager = ( VisibilityChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new VisibilityChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnColumnVisibilityChanged( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/VisibleColumnsUpdatedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/VisibleColumnsUpdatedEventManager.cs deleted file mode 100644 index 3a07257e..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/VisibleColumnsUpdatedEventManager.cs +++ /dev/null @@ -1,74 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class VisibleColumnsUpdatedEventManager : WeakEventManager - { - private VisibleColumnsUpdatedEventManager() - { - } - - public static void AddListener( ColumnCollection source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( ColumnCollection source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - ColumnCollection columns = ( ColumnCollection )source; - columns.VisibleColumnsUpdated += new EventHandler( this.OnVisibleColumnsUpdated ); - } - - protected override void StopListening( object source ) - { - ColumnCollection columns = ( ColumnCollection )source; - columns.VisibleColumnsUpdated -= new EventHandler( this.OnVisibleColumnsUpdated ); - } - - private static VisibleColumnsUpdatedEventManager CurrentManager - { - get - { - Type managerType = typeof( VisibleColumnsUpdatedEventManager ); - VisibleColumnsUpdatedEventManager currentManager = ( VisibleColumnsUpdatedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new VisibleColumnsUpdatedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnVisibleColumnsUpdated( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/WeakDataGridContextKey.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/WeakDataGridContextKey.cs index 1466ab01..7467129b 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/WeakDataGridContextKey.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(Generator)/WeakDataGridContextKey.cs @@ -15,28 +15,26 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Text; +using System.Diagnostics; namespace Xceed.Wpf.DataGrid { - internal class WeakDataGridContextKey + internal sealed class WeakDataGridContextKey { - public WeakDataGridContextKey( DataGridContext dataGridContext ) + internal WeakDataGridContextKey( DataGridContext dataGridContext ) { - DataGridContext parentDataGridContext = dataGridContext.ParentDataGridContext; - int level = 0; + var parentDataGridContext = dataGridContext.ParentDataGridContext; + var level = 0; + while( parentDataGridContext != null ) { level++; parentDataGridContext = parentDataGridContext.ParentDataGridContext; } - System.Diagnostics.Debug.Assert( ( ( level == 0 ) || ( dataGridContext.SourceDetailConfiguration != null ) ), - "A child dataGridContext must have a SourceDetailConfiguration." ); + Debug.Assert( ( ( level == 0 ) || ( dataGridContext.SourceDetailConfiguration != null ) ), "A child dataGridContext must have a SourceDetailConfiguration." ); - m_sourceDetailConfigurationRelationName = ( dataGridContext.SourceDetailConfiguration != null ) ? - dataGridContext.SourceDetailConfiguration.RelationName : string.Empty; + m_sourceDetailConfigurationRelationName = ( dataGridContext.SourceDetailConfiguration != null ) ? dataGridContext.SourceDetailConfiguration.RelationName : string.Empty; if( level > 0 ) { @@ -45,13 +43,13 @@ namespace Xceed.Wpf.DataGrid // Build the tree of master items. m_weakItemsTree = new WeakReference[ level ]; - DataGridContext tempDataGridContext = dataGridContext; + var tempDataGridContext = dataGridContext; for( int i = level - 1; i >= 0; i-- ) { // Ensure to get a reference to the System.Data.DataRow when doing a // save/restore of a System.Data.DataRowView since the view is recreated // for every detail views - object parentItem = ItemsSourceHelper.TryGetDataRowFromDataItem( tempDataGridContext.ParentItem ); + var parentItem = ItemsSourceHelper.TryGetDataRowFromDataItem( tempDataGridContext.ParentItem ); m_weakItemsTree[ i ] = new WeakReference( parentItem ); @@ -59,67 +57,33 @@ namespace Xceed.Wpf.DataGrid } } - this.Initialize(); + m_hashCode = WeakDataGridContextKey.CalculateHashCode( m_sourceDetailConfigurationRelationName, m_weakItemsTree ); } - private void Initialize() - { - m_cachedHash = 0; - - if( !string.IsNullOrEmpty( m_sourceDetailConfigurationRelationName ) ) - m_cachedHash = m_sourceDetailConfigurationRelationName.GetHashCode(); - - if( m_weakItemsTree != null ) - { - // We use this hashing algorithm in order to get a different hashCode - // when the same values are in a different order in the object array. - int weakItemsTreeLength = m_weakItemsTree.Length; - for( int i = 0; i < weakItemsTreeLength; i++ ) - { - object item = m_weakItemsTree[ i ].Target; - - System.Diagnostics.Debug.Assert( item != null, "Item should still be referenced by the Child DataGridContext at this point!." ); - - m_cachedHash ^= item.GetHashCode(); - m_cachedHash += ( m_cachedHash << 10 ); - m_cachedHash ^= ( m_cachedHash >> 6 ); - } - } - } - - private int m_cachedHash; - public override int GetHashCode() { - return m_cachedHash; + return m_hashCode; } - private WeakReference[] m_weakItemsTree; - private string m_sourceDetailConfigurationRelationName; - public override bool Equals( object obj ) { - WeakDataGridContextKey weakDataGridContextKey = obj as WeakDataGridContextKey; - - if( weakDataGridContextKey == null ) + var target = obj as WeakDataGridContextKey; + if( ( target == null ) || ( m_hashCode != target.m_hashCode ) ) return false; - if( m_cachedHash != weakDataGridContextKey.m_cachedHash ) + if( m_sourceDetailConfigurationRelationName != target.m_sourceDetailConfigurationRelationName ) return false; - if( m_sourceDetailConfigurationRelationName != weakDataGridContextKey.m_sourceDetailConfigurationRelationName ) - return false; - - int dataGridContextStatusKeyLength = ( weakDataGridContextKey.m_weakItemsTree == null ) ? 0 : weakDataGridContextKey.m_weakItemsTree.Length; - int myLength = ( m_weakItemsTree == null ) ? 0 : m_weakItemsTree.Length; + var dataGridContextStatusKeyLength = ( target.m_weakItemsTree == null ) ? 0 : target.m_weakItemsTree.Length; + var myLength = ( m_weakItemsTree == null ) ? 0 : m_weakItemsTree.Length; if( myLength != dataGridContextStatusKeyLength ) return false; - for( int i = 0; i < dataGridContextStatusKeyLength; i++ ) + for( var i = 0; i < dataGridContextStatusKeyLength; i++ ) { - object sourceItem = m_weakItemsTree[ i ].Target; - object targetItem = weakDataGridContextKey.m_weakItemsTree[ i ].Target; + var sourceItem = m_weakItemsTree[ i ].Target; + var targetItem = target.m_weakItemsTree[ i ].Target; if( !object.Equals( sourceItem, targetItem ) ) return false; @@ -127,6 +91,34 @@ namespace Xceed.Wpf.DataGrid return true; } - } + private static int CalculateHashCode( string relationName, WeakReference[] items ) + { + var hashCode = ( !string.IsNullOrEmpty( relationName ) ) ? relationName.GetHashCode() : 0; + + if( items != null ) + { + // We use this hashing algorithm in order to get a different hashCode + // when the same values are in a different order in the object array. + for( var i = 0; i < items.Length; i++ ) + { + var item = items[ i ].Target; + Debug.Assert( item != null, "Item should still be referenced by the Child DataGridContext at this point!." ); + + if( item == null ) + continue; + + hashCode ^= item.GetHashCode(); + hashCode += ( hashCode << 10 ); + hashCode ^= ( hashCode >> 6 ); + } + } + + return hashCode; + } + + private readonly WeakReference[] m_weakItemsTree; + private readonly string m_sourceDetailConfigurationRelationName; + private readonly int m_hashCode; + } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/ColumnDraggableStatusEnum.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/ColumnDraggableStatusEnum.cs new file mode 100644 index 00000000..96f85cfe --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/ColumnDraggableStatusEnum.cs @@ -0,0 +1,25 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +namespace Xceed.Wpf.DataGrid +{ + public enum ColumnDraggableStatus + { + Draggable = 0, + FirstUndraggable, + LastUndraggable, + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/InsertionModeEnum.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/DataGridDragBehaviorEnum.cs similarity index 89% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/InsertionModeEnum.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/DataGridDragBehaviorEnum.cs index 1b50e898..f0783ca8 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/InsertionModeEnum.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/DataGridDragBehaviorEnum.cs @@ -1,29 +1,29 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Xceed.Wpf.DataGrid -{ - public enum InsertionMode - { - Default, - Continuous, - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Xceed.Wpf.DataGrid +{ + public enum DataGridDragBehavior + { + DragDrop = 0, + Select + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/FilterOperatorPrecedenceEnum.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/FilterOperatorPrecedenceEnum.cs deleted file mode 100644 index cbe2d8f3..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/FilterOperatorPrecedenceEnum.cs +++ /dev/null @@ -1,50 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; - -namespace Xceed.Wpf.DataGrid -{ - /// - /// The precedence value of an expression operator determining the order in which the - /// parameters of the expression will be consumed. A smaller value means a greater - /// priority. The values closely follows the standard operator precedences. This type - /// should not be confused with the FilterTokenPriority enum. - /// - internal enum FilterOperatorPrecedence - { - /// - /// 0: RelationalOperator (=, >, <, ...) - /// - RelationalOperator, - /// - /// 1: Not operator - /// - NotOperator, - /// - /// 2: And operator - /// - AndOperator, - /// - /// 3: Or operator - /// - OrOperator, - /// - /// 4: Default priority - /// - Default - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/FilterTokenPriorityEnum.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/FilterTokenPriorityEnum.cs deleted file mode 100644 index 702627fd..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/FilterTokenPriorityEnum.cs +++ /dev/null @@ -1,51 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; - -namespace Xceed.Wpf.DataGrid -{ - /// - /// The priority value of an expression operator determining the order in which the - /// operator will be parsed. A smaller value means a greater priority. The operator - /// having an impact on the interpretation of its surrounding operators should have - /// a greater priority than those that do not. This type should not be confused with - /// the FilterOperatorPrecedence enum. - /// - internal enum FilterTokenPriority - { - /// - /// 0: And operator - /// - AndOperator, - /// - /// 1: Or operator - /// - OrOperator, - /// - /// 2: Not operator - /// - NotOperator, - /// - /// 3: RelationalOperator (=, >, <, ...) - /// - RelationalOperator, - /// - /// 4: Default priority - /// - Default - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/AutoFilterModeEnum.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/LocationTypeEnum.cs similarity index 73% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/AutoFilterModeEnum.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/LocationTypeEnum.cs index 67ea8ba4..93651a88 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/AutoFilterModeEnum.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/LocationTypeEnum.cs @@ -1,30 +1,28 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; - -namespace Xceed.Wpf.DataGrid -{ - // Defines the way the filter acts on Filter defined on each column of a Row - internal enum AutoFilterMode - { - None, - And, - Or - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + + +namespace Xceed.Wpf.DataGrid +{ + internal enum LocationType + { + Column, + Start, + End, + Splitter, + Orphan, + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/PropertyRouteSegmentTypeEnum.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/PropertyRouteSegmentTypeEnum.cs new file mode 100644 index 00000000..506316aa --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/PropertyRouteSegmentTypeEnum.cs @@ -0,0 +1,27 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + + +namespace Xceed.Wpf.DataGrid +{ + internal enum PropertyRouteSegmentType : byte + { + Self, + Property, + Indexer, + Other, + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/FilterCriteriaModeEnum.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/SelectionBehaviorEnum.cs similarity index 87% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/FilterCriteriaModeEnum.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/SelectionBehaviorEnum.cs index 1a23c1f2..5cec2603 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/FilterCriteriaModeEnum.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(enums)/SelectionBehaviorEnum.cs @@ -1,27 +1,25 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; - -namespace Xceed.Wpf.DataGrid -{ - public enum FilterCriteriaMode - { - None, - And, - Or - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +namespace Xceed.Wpf.DataGrid +{ + public enum SelectionBehavior + { + Default, + None, + All + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/AssemblyVersionInfo.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/AssemblyVersionInfo.cs index 86729f0c..c12a30d1 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/AssemblyVersionInfo.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/AssemblyVersionInfo.cs @@ -19,7 +19,7 @@ internal static class _XceedVersionInfo { [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] - public const string BaseVersion = "3.2"; + public const string BaseVersion = "3.3"; [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] public const string Version = BaseVersion + ".0.0"; [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/AutoResetFlagFactory.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/AutoResetFlagFactory.cs index fd06a03b..29221f10 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/AutoResetFlagFactory.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/AutoResetFlagFactory.cs @@ -59,10 +59,9 @@ namespace Xceed.Wpf.DataGrid private void Dispose( bool disposing ) { - var target = m_target; - // The disposed method has already been called at least once. - if( Interlocked.CompareExchange( ref m_target, null, target ) == null ) + var target = Interlocked.Exchange( ref m_target, null ); + if( target == null ) return; Debug.Assert( m_target == null ); diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/AutomationPeerExtensions.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/AutomationPeerExtensions.cs deleted file mode 100644 index 842fd91b..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/AutomationPeerExtensions.cs +++ /dev/null @@ -1,181 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Automation.Peers; -using System.Windows.Automation; -using System.Windows.Automation.Provider; - -namespace Xceed.Wpf.DataGrid.Automation -{ - internal static class AutomationPeerExtensions - { - internal static object GetPropertyValue( this AutomationPeer itemPeer, int id ) - { - if( AutomationElementIdentifiers.NameProperty.Id == id ) - { - return itemPeer.GetName(); - } - else if( AutomationElementIdentifiers.AutomationIdProperty.Id == id ) - { - return itemPeer.GetAutomationId(); - } - else if( AutomationElementIdentifiers.ControlTypeProperty.Id == id ) - { - return AutomationPeerExtensions.GetControlType( itemPeer ).Id; - } - else if( SelectionItemPatternIdentifiers.IsSelectedProperty.Id == id ) - { - ISelectionItemProvider selectionItemProvider = itemPeer.GetPattern( PatternInterface.SelectionItem ) as ISelectionItemProvider; - - if( selectionItemProvider == null ) - return null; - - return selectionItemProvider.IsSelected; - } - - return null; - } - - private static ControlType GetControlType( AutomationPeer itemPeer ) - { - switch( itemPeer.GetAutomationControlType() ) - { - case AutomationControlType.Button: - return ControlType.Button; - - case AutomationControlType.Calendar: - return ControlType.Calendar; - - case AutomationControlType.CheckBox: - return ControlType.CheckBox; - - case AutomationControlType.ComboBox: - return ControlType.ComboBox; - - case AutomationControlType.Edit: - return ControlType.Edit; - - case AutomationControlType.Hyperlink: - return ControlType.Hyperlink; - - case AutomationControlType.Image: - return ControlType.Image; - - case AutomationControlType.ListItem: - return ControlType.ListItem; - - case AutomationControlType.List: - return ControlType.List; - - case AutomationControlType.Menu: - return ControlType.Menu; - - case AutomationControlType.MenuBar: - return ControlType.MenuBar; - - case AutomationControlType.MenuItem: - return ControlType.MenuItem; - - case AutomationControlType.ProgressBar: - return ControlType.ProgressBar; - - case AutomationControlType.RadioButton: - return ControlType.RadioButton; - - case AutomationControlType.ScrollBar: - return ControlType.ScrollBar; - - case AutomationControlType.Slider: - return ControlType.Slider; - - case AutomationControlType.Spinner: - return ControlType.Spinner; - - case AutomationControlType.StatusBar: - return ControlType.StatusBar; - - case AutomationControlType.Tab: - return ControlType.Tab; - - case AutomationControlType.TabItem: - return ControlType.TabItem; - - case AutomationControlType.Text: - return ControlType.Text; - - case AutomationControlType.ToolBar: - return ControlType.ToolBar; - - case AutomationControlType.ToolTip: - return ControlType.ToolTip; - - case AutomationControlType.Tree: - return ControlType.Tree; - - case AutomationControlType.TreeItem: - return ControlType.TreeItem; - - case AutomationControlType.Custom: - return ControlType.Custom; - - case AutomationControlType.Group: - return ControlType.Group; - - case AutomationControlType.Thumb: - return ControlType.Thumb; - - case AutomationControlType.DataGrid: - return ControlType.DataGrid; - - case AutomationControlType.DataItem: - return ControlType.DataItem; - - case AutomationControlType.Document: - return ControlType.Document; - - case AutomationControlType.SplitButton: - return ControlType.SplitButton; - - case AutomationControlType.Window: - return ControlType.Window; - - case AutomationControlType.Pane: - return ControlType.Pane; - - case AutomationControlType.Header: - return ControlType.Header; - - case AutomationControlType.HeaderItem: - return ControlType.HeaderItem; - - case AutomationControlType.Table: - return ControlType.Table; - - case AutomationControlType.TitleBar: - return ControlType.TitleBar; - - case AutomationControlType.Separator: - return ControlType.Separator; - } - - return null; - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/AutomationQueryEvents.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/AutomationQueryEvents.cs deleted file mode 100644 index 3bc1d6ba..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/AutomationQueryEvents.cs +++ /dev/null @@ -1,257 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid.Automation -{ - public static class AutomationQueryEvents - { - #region QueryAutomationIdForDetail Event - - public static readonly RoutedEvent QueryAutomationIdForDetailEvent = - EventManager.RegisterRoutedEvent( "QueryAutomationIdForDetail", RoutingStrategy.Bubble, typeof( QueryAutomationIdRoutedEventHandler ), typeof( AutomationQueryEvents ) ); - - public static void AddQueryAutomationIdForDetailHandler( DependencyObject d, QueryAutomationIdRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.AddHandler( AutomationQueryEvents.QueryAutomationIdForDetailEvent, handler ); - } - - public static void RemoveQueryAutomationIdForDetailHandler( DependencyObject d, QueryAutomationIdRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.RemoveHandler( AutomationQueryEvents.QueryAutomationIdForDetailEvent, handler ); - } - - #endregion QueryAutomationIdForDetail Event - - #region QueryHelpTextForDetail Event - - public static readonly RoutedEvent QueryHelpTextForDetailEvent = - EventManager.RegisterRoutedEvent( "QueryHelpTextForDetail", RoutingStrategy.Bubble, typeof( QueryHelpTextRoutedEventHandler ), typeof( AutomationQueryEvents ) ); - - public static void AddQueryHelpTextForDetailHandler( DependencyObject d, QueryHelpTextRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.AddHandler( AutomationQueryEvents.QueryHelpTextForDetailEvent, handler ); - } - - public static void RemoveQueryHelpTextForDetailHandler( DependencyObject d, QueryHelpTextRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.RemoveHandler( AutomationQueryEvents.QueryHelpTextForDetailEvent, handler ); - } - - #endregion QueryHelpTextForDetail Event - - #region QueryItemStatusForDetail Event - - public static readonly RoutedEvent QueryItemStatusForDetailEvent = - EventManager.RegisterRoutedEvent( "QueryItemStatusForDetail", RoutingStrategy.Bubble, typeof( QueryItemStatusRoutedEventHandler ), typeof( AutomationQueryEvents ) ); - - public static void AddQueryItemStatusForDetailHandler( DependencyObject d, QueryItemStatusRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.AddHandler( AutomationQueryEvents.QueryItemStatusForDetailEvent, handler ); - } - - public static void RemoveQueryItemStatusForDetailHandler( DependencyObject d, QueryItemStatusRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.RemoveHandler( AutomationQueryEvents.QueryItemStatusForDetailEvent, handler ); - } - - #endregion QueryItemStatusForDetail Event - - #region QueryItemTypeForDetail Event - - public static readonly RoutedEvent QueryItemTypeForDetailEvent = - EventManager.RegisterRoutedEvent( "QueryItemTypeForDetail", RoutingStrategy.Bubble, typeof( QueryItemTypeRoutedEventHandler ), typeof( AutomationQueryEvents ) ); - - public static void AddQueryItemTypeForDetailHandler( DependencyObject d, QueryItemTypeRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.AddHandler( AutomationQueryEvents.QueryItemTypeForDetailEvent, handler ); - } - - public static void RemoveQueryItemTypeForDetailHandler( DependencyObject d, QueryItemTypeRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.RemoveHandler( AutomationQueryEvents.QueryItemTypeForDetailEvent, handler ); - } - - #endregion QueryItemTypeForDetail Event - - #region QueryNameForDetail Event - - public static readonly RoutedEvent QueryNameForDetailEvent = - EventManager.RegisterRoutedEvent( "QueryNameForDetail", RoutingStrategy.Bubble, typeof( QueryNameRoutedEventHandler ), typeof( AutomationQueryEvents ) ); - - public static void AddQueryNameForDetailHandler( DependencyObject d, QueryNameRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.AddHandler( AutomationQueryEvents.QueryNameForDetailEvent, handler ); - } - - public static void RemoveQueryNameForDetailHandler( DependencyObject d, QueryNameRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.RemoveHandler( AutomationQueryEvents.QueryNameForDetailEvent, handler ); - } - - #endregion QueryNameForDetail Event - - #region QueryAutomationIdForGroup Event - - public static readonly RoutedEvent QueryAutomationIdForGroupEvent = - EventManager.RegisterRoutedEvent( "QueryAutomationIdForGroup", RoutingStrategy.Bubble, typeof( QueryAutomationIdRoutedEventHandler ), typeof( AutomationQueryEvents ) ); - - public static void AddQueryAutomationIdForGroupHandler( DependencyObject d, QueryAutomationIdRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.AddHandler( AutomationQueryEvents.QueryAutomationIdForGroupEvent, handler ); - } - - public static void RemoveQueryAutomationIdForGroupHandler( DependencyObject d, QueryAutomationIdRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.RemoveHandler( AutomationQueryEvents.QueryAutomationIdForGroupEvent, handler ); - } - - #endregion QueryAutomationIdForGroup Event - - #region QueryHelpTextForGroup Event - - public static readonly RoutedEvent QueryHelpTextForGroupEvent = - EventManager.RegisterRoutedEvent( "QueryHelpTextForGroup", RoutingStrategy.Bubble, typeof( QueryHelpTextRoutedEventHandler ), typeof( AutomationQueryEvents ) ); - - public static void AddQueryHelpTextForGroupHandler( DependencyObject d, QueryHelpTextRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.AddHandler( AutomationQueryEvents.QueryHelpTextForGroupEvent, handler ); - } - - public static void RemoveQueryHelpTextForGroupHandler( DependencyObject d, QueryHelpTextRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.RemoveHandler( AutomationQueryEvents.QueryHelpTextForGroupEvent, handler ); - } - - #endregion QueryHelpTextForGroup Event - - #region QueryItemStatusForGroup Event - - public static readonly RoutedEvent QueryItemStatusForGroupEvent = - EventManager.RegisterRoutedEvent( "QueryItemStatusForGroup", RoutingStrategy.Bubble, typeof( QueryItemStatusRoutedEventHandler ), typeof( AutomationQueryEvents ) ); - - public static void AddQueryItemStatusForGroupHandler( DependencyObject d, QueryItemStatusRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.AddHandler( AutomationQueryEvents.QueryItemStatusForGroupEvent, handler ); - } - - public static void RemoveQueryItemStatusForGroupHandler( DependencyObject d, QueryItemStatusRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.RemoveHandler( AutomationQueryEvents.QueryItemStatusForGroupEvent, handler ); - } - - #endregion QueryItemStatusForGroup Event - - #region QueryItemTypeForGroup Event - - public static readonly RoutedEvent QueryItemTypeForGroupEvent = - EventManager.RegisterRoutedEvent( "QueryItemTypeForGroup", RoutingStrategy.Bubble, typeof( QueryItemTypeRoutedEventHandler ), typeof( AutomationQueryEvents ) ); - - public static void AddQueryItemTypeForGroupHandler( DependencyObject d, QueryItemTypeRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.AddHandler( AutomationQueryEvents.QueryItemTypeForGroupEvent, handler ); - } - - public static void RemoveQueryItemTypeForGroupHandler( DependencyObject d, QueryItemTypeRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.RemoveHandler( AutomationQueryEvents.QueryItemTypeForGroupEvent, handler ); - } - - #endregion QueryItemTypeForGroup Event - - #region QueryNameForGroup Event - - public static readonly RoutedEvent QueryNameForGroupEvent = - EventManager.RegisterRoutedEvent( "QueryNameForGroup", RoutingStrategy.Bubble, typeof( QueryNameRoutedEventHandler ), typeof( AutomationQueryEvents ) ); - - public static void AddQueryNameForGroupHandler( DependencyObject d, QueryNameRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.AddHandler( AutomationQueryEvents.QueryNameForGroupEvent, handler ); - } - - public static void RemoveQueryNameForGroupHandler( DependencyObject d, QueryNameRoutedEventHandler handler ) - { - UIElement element = d as UIElement; - - if( element != null ) - element.RemoveHandler( AutomationQueryEvents.QueryNameForGroupEvent, handler ); - } - - #endregion QueryNameForGroup Event - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/CellAutomationPeer.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/CellAutomationPeer.cs deleted file mode 100644 index f3b5daa6..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/CellAutomationPeer.cs +++ /dev/null @@ -1,167 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Automation.Peers; -using System.Windows.Automation.Provider; -using System.Globalization; -using System.Diagnostics; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Automation; - -namespace Xceed.Wpf.DataGrid.Automation -{ - public class CellAutomationPeer : FrameworkElementAutomationPeer, IValueProvider - { - public CellAutomationPeer( Cell owner ) - : base( owner ) - { - } - - public new Cell Owner - { - get - { - return base.Owner as Cell; - } - } - - public override object GetPattern( PatternInterface patternInterface ) - { - switch( patternInterface ) - { - case PatternInterface.Value: - return this; - } - - return base.GetPattern( patternInterface ); - } - - protected override string GetClassNameCore() - { - return "HeaderFooterCell"; - } - - protected override string GetNameCore() - { - string name = AutomationProperties.GetName(this.Owner); - - if( !string.IsNullOrEmpty( name ) ) - return name; - - object title = null; - ColumnBase column = this.Owner.ParentColumn; - - if( column != null ) - title = column.Title; - - if( title == null ) - return string.Empty; - - return string.Format( CultureInfo.CurrentCulture, "{0}", title ); - } - - private void GetTextFromVisualChildren( DependencyObject parentObject, StringBuilder text ) - { - int count = VisualTreeHelper.GetChildrenCount( parentObject ); - - for (int i = 0; i < count; i++) - { - DependencyObject child = VisualTreeHelper.GetChild( parentObject, i ); - - TextBlock childText = child as TextBlock; - - if( childText != null && childText.IsVisible ) - { - if( text.Length > 0 ) - text.Append( ' ' ); - - text.Append( childText.Text ); - } - else - { - TextBox childTextBox = child as TextBox; - - if( childTextBox != null && childTextBox.IsVisible ) - { - if( text.Length > 0 ) - text.Append( ' ' ); - - text.Append( childTextBox.Text ); - } - else - { - this.GetTextFromVisualChildren( child, text ); - } - } - } - } - - protected override string GetAutomationIdCore() - { - string automationId = null; - automationId = base.GetAutomationIdCore(); - - if( string.IsNullOrEmpty( automationId ) ) - { - ColumnBase parentColumn = this.Owner.ParentColumn; - - if( parentColumn != null ) - { - automationId = "Cell_" + this.Owner.ParentColumn.FieldName; - } - else - { - automationId = string.Empty; - } - } - - return automationId; - } - - #region IValueProvider Members - - public bool IsReadOnly - { - get { return true; } - } - - public void SetValue( string value ) - { - throw new NotSupportedException( "Value is read only." ); - } - - public string Value - { - get - { - // Get all the TextBlocks in our children and concatenate them. - StringBuilder text = new StringBuilder( 256 ); - this.GetTextFromVisualChildren( this.Owner, text ); - return text.ToString(); - } - } - - #endregion - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/ColumnManagerCellAutomationPeer.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/ColumnManagerCellAutomationPeer.cs deleted file mode 100644 index 638d30c5..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/ColumnManagerCellAutomationPeer.cs +++ /dev/null @@ -1,158 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Automation.Peers; -using System.Windows.Automation.Provider; -using System.Globalization; - -namespace Xceed.Wpf.DataGrid.Automation -{ - public class ColumnManagerCellAutomationPeer : FrameworkElementAutomationPeer, IInvokeProvider, ITransformProvider - { - public ColumnManagerCellAutomationPeer( ColumnManagerCell owner ) - : base( owner ) - { - } - - public new ColumnManagerCell Owner - { - get - { - return base.Owner as ColumnManagerCell; - } - } - - public override object GetPattern( PatternInterface patternInterface ) - { - switch( patternInterface ) - { - case PatternInterface.Invoke: - case PatternInterface.Transform: - return this; - } - - return base.GetPattern( patternInterface ); - } - - protected override string GetClassNameCore() - { - return "ColumnManagerCell"; - } - - protected override bool IsContentElementCore() - { - return false; - } - - protected override AutomationControlType GetAutomationControlTypeCore() - { - return AutomationControlType.HeaderItem; - } - - protected override string GetNameCore() - { - ColumnBase parentColumn = this.Owner.ParentColumn; - - if( parentColumn == null ) - return string.Empty; - - object title = this.Owner.ParentColumn.Title; - - if( title == null ) - return string.Empty; - - return string.Format( CultureInfo.CurrentCulture, "{0}", title ); - } - - protected override string GetAutomationIdCore() - { - string automationId = null; - automationId = base.GetAutomationIdCore(); - - if( string.IsNullOrEmpty( automationId ) ) - { - ColumnBase parentColumn = this.Owner.ParentColumn; - - if( parentColumn == null ) - return string.Empty; - - return "Cell_" + parentColumn.FieldName; - } - - return string.Empty; - } - - #region IInvokeProvider Members - - void IInvokeProvider.Invoke() - { - this.Owner.DoSort( true ); - } - - #endregion IInvokeProvider Members - - #region ITransformProvider Members - - bool ITransformProvider.CanMove - { - get - { - return false; - } - } - - bool ITransformProvider.CanResize - { - get - { - return true; - } - } - - bool ITransformProvider.CanRotate - { - get - { - return false; - } - } - - void ITransformProvider.Move( double x, double y ) - { - return; - } - - void ITransformProvider.Resize( double width, double height ) - { - ColumnBase parentColumn = this.Owner.ParentColumn; - if( parentColumn == null ) - return; - - this.Owner.DoResize( width, parentColumn ); - } - - void ITransformProvider.Rotate( double degrees ) - { - return; - } - - #endregion ITransformProvider - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/ColumnManagerRowAutomationPeer.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/ColumnManagerRowAutomationPeer.cs deleted file mode 100644 index ef0d65bf..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/ColumnManagerRowAutomationPeer.cs +++ /dev/null @@ -1,50 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Automation.Peers; - -namespace Xceed.Wpf.DataGrid.Automation -{ - public class ColumnManagerRowAutomationPeer : RowAutomationPeer - { - public ColumnManagerRowAutomationPeer( ColumnManagerRow owner ) - : base( owner ) - { - } - - public new ColumnManagerRow Owner - { - get - { - return base.Owner as ColumnManagerRow; - } - } - - protected override bool IsContentElementCore() - { - return false; - } - - protected override AutomationControlType GetAutomationControlTypeCore() - { - return AutomationControlType.Header; - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/DataGridContextAutomationPeer.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/DataGridContextAutomationPeer.cs deleted file mode 100644 index 6c180993..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/DataGridContextAutomationPeer.cs +++ /dev/null @@ -1,1287 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Automation.Peers; -using System.Windows.Automation.Provider; -using System.Windows.Controls; -using System.Windows.Data; -using System.Collections.ObjectModel; -using System.Collections; -using System.Windows; -using System.Windows.Automation; -using System.Collections.Specialized; -using System.Diagnostics; - -namespace Xceed.Wpf.DataGrid.Automation -{ - public class DataGridContextAutomationPeer : AutomationPeer, ISelectionProvider, ITableProvider, IExpandCollapseProvider, IItemContainerProvider - { - internal DataGridContextAutomationPeer( - DataGridControl dataGridControl, - DataGridContext parentDataGridContext, - object parentItem, - DetailConfiguration detailConfiguration ) - { - if( dataGridControl == null ) - throw new ArgumentNullException( "dataGridControl" ); - - if( parentDataGridContext == null ) - { - m_dataGridContext = dataGridControl.DataGridContext; - } - else - { - m_dataGridContext = parentDataGridContext.GetChildContext( parentItem, detailConfiguration ); - } - - if( m_dataGridContext != null ) - m_dataGridContext.Peer = this; - - m_dataGridControl = dataGridControl; - m_parentDataGridContext = parentDataGridContext; - m_parentItem = parentItem; - m_detailConfiguration = detailConfiguration; - - m_dataChildren = new Hashtable( 0 ); - m_headerFooterChildren = new Hashtable( 0 ); - } - - #region DataGridContext Property - - public DataGridContext DataGridContext - { - get - { - return m_dataGridContext; - } - internal set - { - if( m_dataGridContext == value ) - return; - - if( ( m_oldColumnCount != -1 ) && ( m_dataGridContext != null ) ) - { - // We only remove unsubscribe from the event, since it is when we get the child list that we - // subscribe to be aware of the column modification. - m_dataGridContext.Columns.VisibleColumnsUpdated -= new EventHandler( Columns_VisibleColumnsUpdated ); - m_oldColumnCount = -1; - } - - m_dataGridContext = value; - - this.RaiseAutomationEvent( AutomationEvents.StructureChanged ); - } - } - - #endregion - - #region ItemPeers Property - - internal Hashtable ItemPeers - { - get - { - return m_dataChildren; - } - } - - #endregion - - public override object GetPattern( PatternInterface patternInterface ) - { - switch( patternInterface ) - { - case PatternInterface.Table: - case PatternInterface.Grid: - case PatternInterface.Selection: - case PatternInterface.ExpandCollapse: - case PatternInterface.ItemContainer: - return this; - - default: - return null; - } - } - - protected override AutomationControlType GetAutomationControlTypeCore() - { - return AutomationControlType.DataGrid; - } - - protected virtual DataGridItemAutomationPeer CreateItemAutomationPeer( object item, int index ) - { - if( m_dataGridContext == null ) - return null; - - return new DataGridItemAutomationPeer( item, m_dataGridContext, index ); - } - - protected override List GetChildrenCore() - { - if( m_dataGridContext == null ) - return null; - - if( m_oldColumnCount == -1 ) - { - m_oldColumnCount = m_dataGridContext.VisibleColumns.Count; - m_dataGridContext.Columns.VisibleColumnsUpdated += new EventHandler( Columns_VisibleColumnsUpdated ); - } - - CustomItemContainerGenerator itemGenerator = m_dataGridContext.CustomItemContainerGenerator; - IEnumerable items; - int itemsCount; - bool itemsIsAllItems = false; - - // The way Microsoft check if we are called by an automation that support Virtualization. - if( ( ItemContainerPatternIdentifiers.Pattern != null ) && ( m_dataGridControl.ItemsHost is DataGridItemsHost ) ) - { - List realizedItems = itemGenerator.GetRealizedDataItems(); - items = realizedItems; - itemsCount = realizedItems.Count; - } - else - { - CollectionView viewItems = m_dataGridContext.Items; - items = viewItems; - itemsCount = viewItems.Count; - itemsIsAllItems = true; - } - - Hashtable oldDataChildren = m_dataChildren; - Hashtable oldHeaderFooterChildren = m_headerFooterChildren; - - // Get header count - HeadersFootersGeneratorNode headerNode = itemGenerator.Header; - int headersCount = ( headerNode == null ) ? 0 : headerNode.ItemCount; - - // Get footer count - HeadersFootersGeneratorNode footerNode = itemGenerator.Footer; - int footersCount = ( footerNode == null ) ? 0 : footerNode.ItemCount; - - int childrenCount = headersCount + footersCount; - - if( m_parentDataGridContext == null ) - { - // Add the fixed header / footer count to the children - Panel fixedPanel = m_dataGridControl.FixedHeadersHostPanel; - - if( fixedPanel != null ) - { - childrenCount += fixedPanel.Children.Count; - } - - fixedPanel = m_dataGridControl.FixedFootersHostPanel; - - if( fixedPanel != null ) - { - childrenCount += fixedPanel.Children.Count; - } - } - - ReadOnlyObservableCollection groups = m_dataGridContext.Items.Groups; - - if( groups != null ) - { - // Add the group count to the children - childrenCount += groups.Count; - } - else - { - childrenCount += itemsCount; - } - - m_dataChildren = new Hashtable( itemsCount ); - m_headerFooterChildren = new Hashtable( headersCount + footersCount ); - - if( childrenCount == 0 ) - return null; - - List list = new List( childrenCount ); - this.AddChildrenHeaders( headerNode, oldHeaderFooterChildren, list ); - - if( groups != null ) - { - CustomItemContainerGenerator customItemContainerGenerator = m_dataGridContext.CustomItemContainerGenerator; - DataGridGroupAutomationPeer peer; - itemsCount = groups.Count; - - for( int i = 0; i < itemsCount; i++ ) - { - CollectionViewGroup collectionViewGroup = groups[ i ] as CollectionViewGroup; - - if( collectionViewGroup != null ) - { - Group uiGroup = - customItemContainerGenerator.GetGroupFromCollectionViewGroup( null, collectionViewGroup ); - - if( uiGroup != null ) - { - peer = uiGroup.CreateAutomationPeer() as DataGridGroupAutomationPeer; - - if( peer != null ) - list.Add( peer ); - } - } - } - } - else - { - int index = 0; - - foreach( object item in ( IEnumerable )items ) - { - DataGridItemAutomationPeer itemAutomationPeer = - oldDataChildren[ item ] as DataGridItemAutomationPeer; - - if( itemAutomationPeer == null ) - { - if( itemsIsAllItems ) - { - itemAutomationPeer = this.CreateItemAutomationPeer( item, index ); - index++; - } - else - { - itemAutomationPeer = this.CreateItemAutomationPeer( item, -1 ); - } - } - else - { - if( itemsIsAllItems ) - { - itemAutomationPeer.SetIndex( index ); - index++; - } - else - { - itemAutomationPeer.SetIndex( -1 ); - } - } - - // Force EventsSource to be updated - itemAutomationPeer.GetWrapperPeer(); - - if( m_dataChildren[ item ] == null ) - { - list.Add( itemAutomationPeer ); - m_dataChildren[ item ] = itemAutomationPeer; - } - } - } - - this.AddChildrenFooters( footerNode, oldHeaderFooterChildren, list ); - return list; - } - - protected override string GetAcceleratorKeyCore() - { - return string.Empty; - } - - protected override string GetAccessKeyCore() - { - return string.Empty; - } - - protected override string GetAutomationIdCore() - { - string automationId = null; - - if( m_dataGridContext != null ) - { - QueryAutomationIdRoutedEventArgs args = new QueryAutomationIdRoutedEventArgs( - AutomationQueryEvents.QueryAutomationIdForDetailEvent, m_dataGridContext ); - - m_dataGridControl.RaiseEvent( args ); - - if( args.Handled ) - automationId = args.AutomationId; - } - - if( automationId == null ) - return "Detail_" + m_detailConfiguration.RelationName; - - return automationId; - } - - protected override Rect GetBoundingRectangleCore() - { - return Rect.Empty; - } - - protected override string GetClassNameCore() - { - return "DataGridContext"; - } - - protected override Point GetClickablePointCore() - { - return new Point( double.NaN, double.NaN ); - } - - protected override string GetHelpTextCore() - { - if( m_dataGridContext == null ) - return string.Empty; - - QueryHelpTextRoutedEventArgs args = new QueryHelpTextRoutedEventArgs( - AutomationQueryEvents.QueryHelpTextForDetailEvent, m_dataGridContext ); - - m_dataGridControl.RaiseEvent( args ); - string helpText = null; - - if( args.Handled ) - helpText = args.HelpText; - - return ( helpText ?? string.Empty ); - } - - protected override string GetItemStatusCore() - { - if( m_dataGridContext == null ) - return string.Empty; - - QueryItemStatusRoutedEventArgs args = new QueryItemStatusRoutedEventArgs( - AutomationQueryEvents.QueryItemStatusForDetailEvent, m_dataGridContext ); - - m_dataGridControl.RaiseEvent( args ); - string itemStatus = null; - - if( args.Handled ) - itemStatus = args.ItemStatus; - - return ( itemStatus ?? string.Empty ); - } - - protected override string GetItemTypeCore() - { - if( m_dataGridContext == null ) - return string.Empty; - - QueryItemTypeRoutedEventArgs args = new QueryItemTypeRoutedEventArgs( - AutomationQueryEvents.QueryItemTypeForDetailEvent, m_dataGridContext ); - - m_dataGridControl.RaiseEvent( args ); - string itemType = null; - - if( args.Handled ) - itemType = args.ItemType; - - return ( itemType ?? string.Empty ); - } - - protected override AutomationPeer GetLabeledByCore() - { - return null; - } - - protected override string GetNameCore() - { - if( m_dataGridContext == null ) - return string.Empty; - - QueryNameRoutedEventArgs args = new QueryNameRoutedEventArgs( - AutomationQueryEvents.QueryNameForDetailEvent, m_dataGridContext ); - - m_dataGridControl.RaiseEvent( args ); - string name = null; - - if( args.Handled ) - { - name = args.Name; - } - else - { - name = m_dataGridContext.SourceDetailConfiguration.Title as string; - } - - return ( name ?? string.Empty ); - } - - protected override AutomationOrientation GetOrientationCore() - { - return AutomationOrientation.None; - } - - protected override bool HasKeyboardFocusCore() - { - return false; - } - - protected override bool IsContentElementCore() - { - return true; - } - - protected override bool IsControlElementCore() - { - return true; - } - - protected override bool IsEnabledCore() - { - return true; - } - - protected override bool IsKeyboardFocusableCore() - { - return false; - } - - protected override bool IsOffscreenCore() - { - if( m_dataGridContext == null ) - return true; - - if( m_parentDataGridContext == null ) - return false; - - return ( m_parentDataGridContext.CustomItemContainerGenerator.ContainerFromItem( m_dataGridContext.ParentItem ) == null ); - } - - protected override bool IsPasswordCore() - { - return false; - } - - protected override bool IsRequiredForFormCore() - { - return false; - } - - protected override void SetFocusCore() - { - } - - internal DataGridItemAutomationPeer FindOrCreateItemAutomationPeer( object item, int index ) - { - DataGridItemAutomationPeer itemAutomationPeer = m_dataChildren[ item ] as DataGridItemAutomationPeer; - - if( itemAutomationPeer == null ) - { - itemAutomationPeer = this.CreateItemAutomationPeer( item, index ); - } - else - { - itemAutomationPeer.SetIndex( index ); - } - - // Force EventsSource to be updated - itemAutomationPeer.GetWrapperPeer(); - return itemAutomationPeer; - } - - internal IRawElementProviderSimple GetRawElementProviderSimple() - { - return this.ProviderFromPeer( this ); - } - - internal DataGridItemAutomationPeer GetItemAutomationPeer( object item ) - { - // Force the creation of the Children. - this.GetChildren(); - return m_dataChildren[ item ] as DataGridItemAutomationPeer; - } - - internal DataGridItemAutomationPeer CreateItemAutomationPeerInternal( object item, int index ) - { - return this.CreateItemAutomationPeer( item, index ); - } - - internal void RaiseSelectionEvents( IList unselectedItems, IList selectedItems ) - { - if( m_dataChildren.Count == 0 ) - { - this.RaiseAutomationEvent( AutomationEvents.SelectionPatternOnInvalidated ); - return; - } - - int currentSelectedItemCount = ( m_dataGridContext == null ) ? 0 : m_dataGridContext.SelectedItemsStore.Count; - int selectedItemsCount = selectedItems.Count; - int unselectedItemsCount = unselectedItems.Count; - - if( currentSelectedItemCount == 1 ) - { - object item; - - try - { - // GetItem() can throw if the DataVirtualizing source don't have that item anymore. - item = m_dataGridContext.SelectedItemsStore[ 0 ].GetItem( m_dataGridContext, 0 ); - } - catch - { - item = null; - } - - if( item != null ) - { - DataGridItemAutomationPeer peer = m_dataChildren[ item ] as DataGridItemAutomationPeer; - - if( peer != null ) - peer.RaiseAutomationEvent( AutomationEvents.SelectionItemPatternOnElementSelected ); - } - else - { - this.RaiseAutomationEvent( AutomationEvents.SelectionPatternOnInvalidated ); - } - } - else if( ( selectedItemsCount + unselectedItemsCount ) > 20 ) - { - this.RaiseAutomationEvent( AutomationEvents.SelectionPatternOnInvalidated ); - } - else - { - for( int i = 0; i < selectedItemsCount; i++ ) - { - object item; - - try - { - // Underlying GetItem() can throw if the DataVirtualizing source don't have that item anymore. - item = selectedItems[ i ]; - } - catch - { - item = null; - } - - if( item != null ) - { - DataGridItemAutomationPeer peer = m_dataChildren[ item ] as DataGridItemAutomationPeer; - - if( peer != null ) - peer.RaiseAutomationEvent( AutomationEvents.SelectionItemPatternOnElementAddedToSelection ); - } - else - { - this.RaiseAutomationEvent( AutomationEvents.SelectionPatternOnInvalidated ); - return; - } - } - - for( int i = 0; i < unselectedItemsCount; i++ ) - { - object item; - - try - { - // Underlying GetItem() can throw if the DataVirtualizing source don't have that item anymore. - item = unselectedItems[ i ]; - } - catch - { - item = null; - } - - if( item != null ) - { - DataGridItemAutomationPeer peer = m_dataChildren[ item ] as DataGridItemAutomationPeer; - - if( peer != null ) - peer.RaiseAutomationEvent( AutomationEvents.SelectionItemPatternOnElementRemovedFromSelection ); - } - else - { - this.RaiseAutomationEvent( AutomationEvents.SelectionPatternOnInvalidated ); - return; - } - } - } - } - - internal DataGridContextAutomationPeer GetDetailPeer( object parentItem, DetailConfiguration detailConfig ) - { - DataGridItemAutomationPeer itemAutomationPeer = m_dataChildren[ parentItem ] as DataGridItemAutomationPeer; - - if( itemAutomationPeer == null ) - return null; - - return itemAutomationPeer.GetDetailPeer( detailConfig ); - } - - internal List GetColumnHeadersPeer() - { - if( m_dataGridContext == null ) - return null; - - List list = new List( 16 ); - this.AddChildrenHeaders( m_dataGridContext.CustomItemContainerGenerator.Header, m_headerFooterChildren, list ); - this.AddChildrenFooters( m_dataGridContext.CustomItemContainerGenerator.Footer, m_headerFooterChildren, list ); - int listCount = list.Count; - - List columnHeaders = new List( listCount ); - - for( int i = 0; i < listCount; i++ ) - { - HeaderFooterItemAutomationPeer headerFooterItemPeer = list[ i ] as HeaderFooterItemAutomationPeer; - - if( headerFooterItemPeer == null ) - continue; - - if( headerFooterItemPeer.GetAutomationControlType() == AutomationControlType.Header ) - columnHeaders.Add( headerFooterItemPeer ); - } - - return columnHeaders; - } - - private void Columns_VisibleColumnsUpdated( object sender, EventArgs e ) - { - if( m_dataGridContext == null ) - return; - - int newCount = m_dataGridContext.VisibleColumns.Count; - - if( newCount != m_oldColumnCount ) - this.RaisePropertyChangedEvent( GridPatternIdentifiers.ColumnCountProperty, m_oldColumnCount, newCount ); - - m_oldColumnCount = newCount; - - // Invalidate the cell peer of all the row to resync with the new column. - foreach( AutomationPeer peer in m_dataChildren.Values ) - { - peer.InvalidatePeer(); - } - } - - private void AddChildrenHeaders( - HeadersFootersGeneratorNode headerNode, - Hashtable oldHeaderFooterChildren, - List list ) - { - if( m_parentDataGridContext == null ) - { - // Add fixed header to the children list - Panel fixedHeaderPanel = m_dataGridControl.FixedHeadersHostPanel; - - if( fixedHeaderPanel != null ) - { - int index = 0; - - foreach( DependencyObject headerFooter in fixedHeaderPanel.Children ) - { - HeaderFooterItem headerFooterItem = headerFooter as HeaderFooterItem; - - if( headerFooterItem != null ) - { - HeaderFooterItemAutomationPeer automationPeer = oldHeaderFooterChildren[ headerFooter ] as HeaderFooterItemAutomationPeer; - - if( automationPeer == null ) - { - automationPeer = new HeaderFooterItemAutomationPeer( m_dataGridContext, headerFooter ); - } - - automationPeer.SetExtraInfo( HeaderFooterItemAutomationPeer.HeaderFooterType.FixedHeader, index ); - m_headerFooterChildren[ headerFooter ] = automationPeer; - list.Add( automationPeer ); - } - - index++; - } - } - } - - if( headerNode != null ) - { - DataGridGroupAutomationPeer.AddHeaderPeer( m_dataGridContext, headerNode, list, m_headerFooterChildren, oldHeaderFooterChildren ); - } - } - - private void AddChildrenFooters( - HeadersFootersGeneratorNode footerNode, - Hashtable oldHeaderFooterChildren, - List list ) - { - if( m_parentDataGridContext == null ) - { - // Add fixed header to the children list - Panel fixedFooterPanel = m_dataGridControl.FixedFootersHostPanel; - - if( fixedFooterPanel != null ) - { - int index = 0; - - foreach( DependencyObject headerFooter in fixedFooterPanel.Children ) - { - HeaderFooterItem headerFooterItem = headerFooter as HeaderFooterItem; - - if( headerFooterItem != null ) - { - HeaderFooterItemAutomationPeer automationPeer = oldHeaderFooterChildren[ headerFooter ] as HeaderFooterItemAutomationPeer; - - if( automationPeer == null ) - { - automationPeer = new HeaderFooterItemAutomationPeer( m_dataGridContext, headerFooter ); - } - - automationPeer.SetExtraInfo( HeaderFooterItemAutomationPeer.HeaderFooterType.FixedFooter, index ); - m_headerFooterChildren[ headerFooter ] = automationPeer; - list.Add( automationPeer ); - } - - index++; - } - } - } - - if( footerNode != null ) - { - DataGridGroupAutomationPeer.AddFooterPeer( m_dataGridContext, footerNode, list, m_headerFooterChildren, oldHeaderFooterChildren ); - } - } - - #region ISelectionProvider Members - - bool ISelectionProvider.CanSelectMultiple - { - get - { - return m_dataGridControl.SelectionModeToUse != SelectionMode.Single; - } - } - - IRawElementProviderSimple[] ISelectionProvider.GetSelection() - { - if( m_dataGridContext == null ) - return null; - - IList selectedItems = m_dataGridContext.SelectedItems; - int count = m_dataGridContext.SelectedItems.Count; - - if( ( count <= 0 ) || ( m_dataChildren.Count <= 0 ) ) - return null; - - List list = new List( count ); - - for( int i = 0; i < count; i++ ) - { - DataGridItemAutomationPeer peer = - m_dataChildren[ selectedItems[ i ] ] as DataGridItemAutomationPeer; - - if( peer != null ) - list.Add( this.ProviderFromPeer( peer ) ); - } - - return list.ToArray(); - } - - bool ISelectionProvider.IsSelectionRequired - { - get - { - return false; - } - } - - #endregion ISelectionProvider Members - - #region ITableProvider Members - - IRawElementProviderSimple[] ITableProvider.GetColumnHeaders() - { - List list = this.GetColumnHeadersPeer(); - IRawElementProviderSimple[] rawElementProviderSimples = new IRawElementProviderSimple[ list.Count ]; - - for( int i = 0; i < rawElementProviderSimples.Length; i++ ) - { - rawElementProviderSimples[ i ] = this.ProviderFromPeer( list[ i ] ); - } - - return rawElementProviderSimples; - } - - IRawElementProviderSimple[] ITableProvider.GetRowHeaders() - { - return new IRawElementProviderSimple[ 0 ]; - } - - RowOrColumnMajor ITableProvider.RowOrColumnMajor - { - get - { - return RowOrColumnMajor.RowMajor; - } - } - - #endregion - - #region IGridProvider Members - - int IGridProvider.ColumnCount - { - get - { - if( m_dataGridContext == null ) - return 0; - - return m_dataGridContext.VisibleColumns.Count; - } - } - - IRawElementProviderSimple IGridProvider.GetItem( int row, int column ) - { - if( m_dataGridContext == null ) - return null; - - // Here we only consider data item. No header / footer are part of the IGridProvider. - CollectionView items = m_dataGridContext.Items; - - if( ( row < 0 ) || ( row >= items.Count ) ) - throw new ArgumentOutOfRangeException( "row" ); - - ReadOnlyObservableCollection visibleColumns = m_dataGridContext.VisibleColumns; - - if( ( column < 0 ) || ( column >= visibleColumns.Count ) ) - throw new ArgumentOutOfRangeException( "column" ); - - object item = m_dataGridContext.Items.GetItemAt( row ); - DataGridItemAutomationPeer itemPeer = m_dataChildren[ item ] as DataGridItemAutomationPeer; - - if( itemPeer == null ) - { - // If the item is not found in the cache, try to force is creation in the caching. - CollectionViewGroup[] groups; - this.GetParentGroupsContainingItemIndex( row, out groups ); - - this.ForceChildrenCaching( groups ); - itemPeer = m_dataChildren[ item ] as DataGridItemAutomationPeer; - } - - if( itemPeer == null ) - return null; - - DataGridItemCellAutomationPeer cellPeer = itemPeer.GetDataGridItemCellPeer( visibleColumns[ column ] ); - - if( cellPeer == null ) - return null; - - return this.ProviderFromPeer( cellPeer ); - } - - int IGridProvider.RowCount - { - get - { - if( m_dataGridContext == null ) - return 0; - - return m_dataGridContext.Items.Count; - } - } - - private void ForceChildrenCaching( CollectionViewGroup[] groups ) - { - List subAutomationPeers = this.GetChildren(); - - foreach( CollectionViewGroup group in groups ) - { - Debug.Assert( !( group is DataGridCollectionViewGroupRoot ) ); - bool groupFound = false; - - foreach( AutomationPeer automationPeer in subAutomationPeers ) - { - DataGridGroupAutomationPeer groupAutomationPeer = automationPeer as DataGridGroupAutomationPeer; - - if( groupAutomationPeer == null ) - continue; - - if( groupAutomationPeer.Owner.CollectionViewGroup == group ) - { - subAutomationPeers = groupAutomationPeer.GetChildren(); - groupFound = true; - break; - } - } - - if( !groupFound ) - break; - } - } - - private void GetParentGroupsContainingItemIndex( int index, out CollectionViewGroup[] parentGroups ) - { - DataGridCollectionView collectionView = m_dataGridContext.ItemsSourceCollection as DataGridCollectionView; - - if( collectionView != null ) - { - RawItem rawItem = collectionView.GetRawItemAt( index ); - List groupList = new List( 16 ); - DataGridCollectionViewGroup parentGroup = rawItem.ParentGroup; - - while( ( parentGroup != null ) && !( parentGroup is DataGridCollectionViewGroupRoot ) ) - { - groupList.Add( parentGroup ); - parentGroup = parentGroup.Parent; - } - - groupList.Reverse(); - parentGroups = groupList.ToArray(); - } - else - { - CollectionView items = m_dataGridContext.Items; - ReadOnlyObservableCollection groups = items.Groups; - - if( groups != null ) - { - List groupList = new List( 16 ); - this.GetParentGroupsContainingItemIndex( index, groups, groupList ); - parentGroups = groupList.ToArray(); - } - else - { - parentGroups = new DataGridCollectionViewGroup[ 0 ]; - } - } - } - - private void GetParentGroupsContainingItemIndex( - int indexOffset, - ReadOnlyObservableCollection rootGroups, - List parentGroups ) - { - int oldCurrentCount = 0; - int currentCount = 0; - - foreach( CollectionViewGroup group in rootGroups ) - { - currentCount += group.GetItemCount(); - - if( currentCount > indexOffset ) - { - parentGroups.Add( group ); - - if( !group.IsBottomLevel ) - { - this.GetParentGroupsContainingItemIndex( - indexOffset - oldCurrentCount, - ( ReadOnlyObservableCollection )group.GetItems(), - parentGroups ); - } - - return; - } - - oldCurrentCount = currentCount; - } - } - - #endregion - - #region IExpandCollapseProvider Members - - void IExpandCollapseProvider.Collapse() - { - if( m_parentDataGridContext == null ) - return; - - m_parentDataGridContext.CollapseDetails( m_parentItem ); - this.DataGridContext = null; - } - - void IExpandCollapseProvider.Expand() - { - if( m_parentDataGridContext == null ) - return; - - m_parentDataGridContext.ExpandDetails( m_parentItem ); - Debug.Assert( m_dataGridContext != null ); - } - - ExpandCollapseState IExpandCollapseProvider.ExpandCollapseState - { - get - { - if( m_parentDataGridContext == null ) - return ExpandCollapseState.Expanded; - - return ( m_dataGridContext == null ) ? - ExpandCollapseState.Collapsed : ExpandCollapseState.Expanded; - } - } - - #endregion - - #region IItemContainerProvider Members - - public IRawElementProviderSimple FindItemByProperty( IRawElementProviderSimple startAfter, int propertyId, object value ) - { - if( ( propertyId != 0 ) && ( !DataGridContextAutomationPeer.IsPropertySupportedForFindItem( propertyId ) ) ) - { - throw new ArgumentException( "Property not supported" ); - } - - if( m_dataGridContext == null ) - return null; - - CollectionView items = m_dataGridContext.Items; - int itemsCount = ( items == null ) ? 0 : items.Count; - - DataGridItemAutomationPeer startAfterItemPeer = null; - HeaderFooterItemAutomationPeer startAfterHeaderFooterPeer = null; - - if( startAfter != null ) - { - AutomationPeer startAfterPeer = this.PeerFromProvider( startAfter ); - - if( startAfterPeer == null ) - return null; - - startAfterItemPeer = startAfterPeer as DataGridItemAutomationPeer; - startAfterHeaderFooterPeer = startAfterPeer as HeaderFooterItemAutomationPeer; - } - - int startIndex = 0; - - // Get header count - HeadersFootersGeneratorNode headerNode = m_dataGridContext.CustomItemContainerGenerator.Header; - int headersCount = ( headerNode == null ) ? 0 : headerNode.ItemCount; - int fixedHeadersCount = 0; - Panel fixedHeadersPanel = null; - - // Get footer count - HeadersFootersGeneratorNode footerNode = m_dataGridContext.CustomItemContainerGenerator.Footer; - int footersCount = ( footerNode == null ) ? 0 : footerNode.ItemCount; - int fixedFootersCount = 0; - Panel fixedFootersPanel = null; - - if( m_parentDataGridContext == null ) - { - // Add the fixed header / footer count to the children - fixedHeadersPanel = m_dataGridControl.FixedHeadersHostPanel; - fixedHeadersCount = ( fixedHeadersPanel != null ) ? fixedHeadersPanel.Children.Count : 0; - fixedFootersPanel = m_dataGridControl.FixedFootersHostPanel; - fixedFootersCount = ( fixedFootersPanel != null ) ? fixedFootersPanel.Children.Count : 0; - } - - int childrenCount = headersCount + fixedHeadersCount + footersCount + fixedFootersCount + itemsCount; - - if( startAfterItemPeer != null ) - { - startIndex = fixedHeadersCount + headersCount + startAfterItemPeer.Index + 1; - } - else if( startAfterHeaderFooterPeer != null ) - { - startIndex = startAfterHeaderFooterPeer.Index + 1; - - switch( startAfterHeaderFooterPeer.Type ) - { - case HeaderFooterItemAutomationPeer.HeaderFooterType.FixedHeader: - { - break; - } - case HeaderFooterItemAutomationPeer.HeaderFooterType.Header: - { - startIndex += fixedHeadersCount; - break; - } - case HeaderFooterItemAutomationPeer.HeaderFooterType.Footer: - { - startIndex += fixedHeadersCount + headersCount + itemsCount; - break; - } - case HeaderFooterItemAutomationPeer.HeaderFooterType.FixedFooter: - { - startIndex += fixedHeadersCount + headersCount + footersCount + itemsCount; - break; - } - } - } - - // Force a children refresh and update our inner caching - this.GetChildren(); - - if( propertyId == 0 ) - { - AutomationPeer peer = this.GetPeerForChildrenIndex( startIndex ); - - if( peer == null ) - return null; - - return this.ProviderFromPeer( peer ); - } - - object propertyValue = null; - - // Search in footer/Fixed footer first - if( footersCount + fixedFootersCount > 0 ) - { - int footerStartIndex = Math.Max( startIndex, childrenCount - footersCount - fixedFootersCount ); - - for( int i = startIndex; i < childrenCount; i++ ) - { - AutomationPeer peer = this.GetPeerForChildrenIndex( i ); - - if( peer != null ) - { - try - { - propertyValue = peer.GetPropertyValue( propertyId ); - } - catch( Exception exception ) - { - if( exception is ElementNotAvailableException ) - { - continue; - } - } - - if( object.Equals( value, propertyValue ) ) - { - return this.ProviderFromPeer( peer ); - } - } - } - - childrenCount -= footersCount + fixedFootersCount; - } - - // Search in the header/Fixed header and data item - for( int i = startIndex; i < childrenCount; i++ ) - { - AutomationPeer peer = this.GetPeerForChildrenIndex( i ); - - if( peer != null ) - { - try - { - propertyValue = peer.GetPropertyValue( propertyId ); - } - catch( Exception exception ) - { - if( exception is ElementNotAvailableException ) - { - continue; - } - } - - if( object.Equals( value, propertyValue ) ) - { - return this.ProviderFromPeer( peer ); - } - } - } - - return null; - } - - private AutomationPeer GetPeerForChildrenIndex( int index ) - { - int fixedHeadersCount = 0; - Panel fixedHeadersPanel = null; - int fixedFootersCount = 0; - Panel fixedFootersPanel = null; - - if( m_parentDataGridContext == null ) - { - fixedHeadersPanel = m_dataGridControl.FixedHeadersHostPanel; - fixedHeadersCount = ( fixedHeadersPanel != null ) ? fixedHeadersPanel.Children.Count : 0; - fixedFootersPanel = m_dataGridControl.FixedFootersHostPanel; - fixedFootersCount = ( fixedFootersPanel != null ) ? fixedFootersPanel.Children.Count : 0; - } - - if( index < fixedHeadersCount ) - { - UIElement element = fixedHeadersPanel.Children[ index ]; - AutomationPeer automationPeer = m_headerFooterChildren[ element ] as AutomationPeer; - Debug.Assert( automationPeer != null ); - - if( automationPeer == null ) - return null; - - return automationPeer; - } - else - { - index -= fixedHeadersCount; - HeadersFootersGeneratorNode headerNode = m_dataGridContext.CustomItemContainerGenerator.Header; - int headersCount = ( headerNode == null ) ? 0 : headerNode.ItemCount; - - if( index < headersCount ) - { - object item = headerNode.GetAt( index ); - AutomationPeer automationPeer = m_headerFooterChildren[ item ] as AutomationPeer; - Debug.Assert( automationPeer != null ); - return automationPeer; - } - else - { - index -= headersCount; - CollectionView items = m_dataGridContext.Items; - int itemsCount = ( items == null ) ? 0 : items.Count; - - if( index < itemsCount ) - { - return this.FindOrCreateItemAutomationPeer( items.GetItemAt( index ), index ); - } - else - { - index -= itemsCount; - HeadersFootersGeneratorNode footerNode = m_dataGridContext.CustomItemContainerGenerator.Footer; - int footersCount = ( footerNode == null ) ? 0 : footerNode.ItemCount; - - if( index < footersCount ) - { - object item = footerNode.GetAt( index ); - AutomationPeer automationPeer = m_headerFooterChildren[ item ] as AutomationPeer; - Debug.Assert( automationPeer != null ); - return automationPeer; - } - else - { - index -= footersCount; - - if( index < fixedFootersCount ) - { - UIElement element = fixedFootersPanel.Children[ index ]; - AutomationPeer automationPeer = m_headerFooterChildren[ element ] as AutomationPeer; - Debug.Assert( automationPeer != null ); - return automationPeer; - } - } - } - } - } - - return null; - } - - private static bool IsPropertySupportedForFindItem( int id ) - { - return ( ( AutomationElementIdentifiers.NameProperty.Id == id ) - || ( AutomationElementIdentifiers.AutomationIdProperty.Id == id ) - || ( AutomationElementIdentifiers.ControlTypeProperty.Id == id ) - || ( SelectionItemPatternIdentifiers.IsSelectedProperty.Id == id ) ); - } - - #endregion - - private DataGridControl m_dataGridControl; - private DataGridContext m_dataGridContext; - private DataGridContext m_parentDataGridContext; - private object m_parentItem; - private DetailConfiguration m_detailConfiguration; - - private Hashtable m_dataChildren; - private Hashtable m_headerFooterChildren; - private int m_oldColumnCount = -1; - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/DataGridControlAutomationPeer.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/DataGridControlAutomationPeer.cs deleted file mode 100644 index 4f449eaa..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/DataGridControlAutomationPeer.cs +++ /dev/null @@ -1,114 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Automation.Peers; -using System.Windows.Controls; -using System.Collections; -using System.Windows.Data; -using System.Windows.Automation.Provider; -using System.Collections.ObjectModel; -using System.Windows; - -namespace Xceed.Wpf.DataGrid.Automation -{ - public class DataGridControlAutomationPeer : FrameworkElementAutomationPeer - { - public DataGridControlAutomationPeer( DataGridControl owner ) - : base( owner ) - { - m_innerDataGridContextAutomationPeer = new DataGridContextAutomationPeer( owner, null, null, null ); - m_innerDataGridContextAutomationPeer.EventsSource = this; - } - - #region DataGridControl Property - - public DataGridControl DataGridControl - { - get - { - return this.Owner as DataGridControl; - } - } - - #endregion - - public override object GetPattern( PatternInterface patternInterface ) - { - if( patternInterface == PatternInterface.Scroll ) - { - DataGridControl owner = this.DataGridControl; - ScrollViewer scrollViewer = owner.ScrollViewer; - - if( scrollViewer != null ) - { - AutomationPeer peer = UIElementAutomationPeer.CreatePeerForElement( scrollViewer ); - - if( ( peer != null ) && ( peer is IScrollProvider ) ) - { - peer.EventsSource = this; - return peer; - } - } - } - - return m_innerDataGridContextAutomationPeer.GetPattern( patternInterface ); - } - - protected override List GetChildrenCore() - { - return m_innerDataGridContextAutomationPeer.GetChildren(); - } - - protected override string GetClassNameCore() - { - return "DataGridControl"; - } - - protected override AutomationControlType GetAutomationControlTypeCore() - { - return m_innerDataGridContextAutomationPeer.GetAutomationControlType(); - } - - protected override string GetItemTypeCore() - { - return m_innerDataGridContextAutomationPeer.GetItemType(); - } - - protected override string GetItemStatusCore() - { - return m_innerDataGridContextAutomationPeer.GetItemStatus(); - } - - protected override string GetAutomationIdCore() - { - string automationId = null; - automationId = base.GetAutomationIdCore(); - - if( string.IsNullOrEmpty( automationId ) ) - { - automationId = "DataGridControl"; - } - - return automationId; - } - - private DataGridContextAutomationPeer m_innerDataGridContextAutomationPeer; - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/DataGridGroupAutomationPeer.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/DataGridGroupAutomationPeer.cs deleted file mode 100644 index 0765d04b..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/DataGridGroupAutomationPeer.cs +++ /dev/null @@ -1,705 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Globalization; -using System.Windows; -using System.Windows.Automation; -using System.Windows.Automation.Peers; -using System.Windows.Automation.Provider; -using System.Windows.Data; -using Xceed.Wpf.DataGrid.Utils; - -namespace Xceed.Wpf.DataGrid.Automation -{ - public class DataGridGroupAutomationPeer : AutomationPeer, IExpandCollapseProvider, IItemContainerProvider, IWeakEventListener - { - #region Static Fields - - private static readonly string GroupIsExpandedPropertyName = PropertyHelper.GetPropertyName( ( Group g ) => g.IsExpanded ); - - #endregion - - public DataGridGroupAutomationPeer( Group uiGroupOwner ) - { - if( uiGroupOwner == null ) - throw new ArgumentNullException( "uiGroupOwner" ); - - m_uiGroupOwner = uiGroupOwner; - m_dataChildren = new Hashtable( 0 ); - m_headerFooterChildren = new Hashtable( 0 ); - - PropertyChangedEventManager.AddListener( uiGroupOwner, this, DataGridGroupAutomationPeer.GroupIsExpandedPropertyName ); - } - - #region Owner Property - - public Group Owner - { - get - { - return m_uiGroupOwner; - } - } - - private readonly Group m_uiGroupOwner; - - #endregion - - public override object GetPattern( PatternInterface patternInterface ) - { - if( patternInterface == PatternInterface.ExpandCollapse ) - return this; - - return null; - } - - protected override string GetAcceleratorKeyCore() - { - return string.Empty; - } - - protected override string GetAccessKeyCore() - { - return string.Empty; - } - - protected override AutomationControlType GetAutomationControlTypeCore() - { - return AutomationControlType.Group; - } - - protected override string GetAutomationIdCore() - { - QueryAutomationIdRoutedEventArgs args = new QueryAutomationIdRoutedEventArgs( - AutomationQueryEvents.QueryAutomationIdForGroupEvent, m_uiGroupOwner ); - - m_uiGroupOwner.DataGridContext.DataGridControl.RaiseEvent( args ); - - string automationId = null; - - if( args.Handled ) - automationId = args.AutomationId; - - if( automationId == null ) - { - if( m_uiGroupOwner.Value != null ) - { - return string.Format( - CultureInfo.InvariantCulture, - "Group_{0}:{1}_{2}", - m_uiGroupOwner.Level, m_uiGroupOwner.GroupBy, m_uiGroupOwner.Value ); - } - - return string.Empty; - } - - return automationId; - } - - protected override Rect GetBoundingRectangleCore() - { - return Rect.Empty; - } - - protected override List GetChildrenCore() - { - Group owner = this.Owner; - GroupGeneratorNode generatorNode = owner.GeneratorNode; - - if( generatorNode == null ) - return null; - - DataGridContext dataGridContext = owner.DataGridContext; - - if( dataGridContext == null ) - return null; - - CustomItemContainerGenerator customItemContainerGenerator = dataGridContext.CustomItemContainerGenerator; - IList items; - bool itemsIsAllItems = false; - - // The way Microsoft check if we are called by an automation that support Virtualization. - if( ( ItemContainerPatternIdentifiers.Pattern != null ) && ( owner.IsBottomLevel ) && ( dataGridContext.DataGridControl.ItemsHost is DataGridItemsHost ) ) - { - items = customItemContainerGenerator.GetRealizedDataItemsForGroup( generatorNode ); - } - else - { - items = owner.GetItems(); - itemsIsAllItems = true; - } - - int itemsCount = ( items == null ) ? 0 : items.Count; - Hashtable oldDataChildren = m_dataChildren; - Hashtable oldHeaderFooterChildren = m_headerFooterChildren; - - // Get header count - HeadersFootersGeneratorNode headerNode = generatorNode.GetHeaderNode(); - int headersCount = ( headerNode == null ) ? 0 : headerNode.ItemCount; - - // Get footer count - HeadersFootersGeneratorNode footerNode = generatorNode.GetFooterNode(); - int footersCount = ( footerNode == null ) ? 0 : footerNode.ItemCount; - - int childrenCount = itemsCount + headersCount + footersCount; - m_dataChildren = new Hashtable( itemsCount ); - m_headerFooterChildren = new Hashtable( headersCount + footersCount ); - - if( childrenCount == 0 ) - return null; - - DataGridContextAutomationPeer dataGridContextAutomationPeer = dataGridContext.Peer; - Hashtable dataGridContextItemsPeer = dataGridContextAutomationPeer.ItemPeers; - - DataGridGroupAutomationPeer groupAutomationPeer; - DataGridItemAutomationPeer itemAutomationPeer; - List list = new List( childrenCount ); - - if( headerNode != null ) - { - DataGridGroupAutomationPeer.AddHeaderPeer( dataGridContext, headerNode, list, m_headerFooterChildren, oldHeaderFooterChildren ); - } - - int index = 0; - - for( int i = 0; i < itemsCount; i++ ) - { - object item = items[ i ]; - CollectionViewGroup collectionViewGroup = item as CollectionViewGroup; - - if( collectionViewGroup == null ) - { - if( ( i == 0 ) && ( itemsIsAllItems ) ) - { - GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( generatorNode, 0, 0 ); - nodeHelper.ReverseCalculateIndex(); - index = nodeHelper.SourceDataIndex; - } - - itemAutomationPeer = oldDataChildren[ item ] as DataGridItemAutomationPeer; - - if( itemAutomationPeer == null ) - { - if( itemsIsAllItems ) - { - itemAutomationPeer = dataGridContextAutomationPeer.CreateItemAutomationPeerInternal( item, index + i ); - } - else - { - itemAutomationPeer = dataGridContextAutomationPeer.CreateItemAutomationPeerInternal( item, -1 ); - } - } - else - { - if( itemsIsAllItems ) - { - itemAutomationPeer.SetIndex( index + i ); - } - else - { - itemAutomationPeer.SetIndex( -1 ); - } - } - - // Force EventsSource to be updated - itemAutomationPeer.GetWrapperPeer(); - - if( m_dataChildren[ item ] == null ) - { - Debug.Assert( itemAutomationPeer != null ); - list.Add( itemAutomationPeer ); - m_dataChildren[ item ] = itemAutomationPeer; - - if( dataGridContextItemsPeer[ item ] == null ) - dataGridContextItemsPeer[ item ] = itemAutomationPeer; - } - } - else - { - Group uiGroup = - customItemContainerGenerator.GetGroupFromCollectionViewGroup( this.Owner, collectionViewGroup ); - - if( uiGroup != null ) - { - groupAutomationPeer = uiGroup.CreateAutomationPeer() as DataGridGroupAutomationPeer; - - if( groupAutomationPeer != null ) - list.Add( groupAutomationPeer ); - } - } - } - - if( footerNode != null ) - { - DataGridGroupAutomationPeer.AddFooterPeer( dataGridContext, footerNode, list, m_headerFooterChildren, oldHeaderFooterChildren ); - } - - return list; - } - - protected override string GetClassNameCore() - { - return "DataGridCollectionViewGroup"; - } - - protected override Point GetClickablePointCore() - { - return new Point( double.NaN, double.NaN ); - } - - protected override string GetHelpTextCore() - { - QueryHelpTextRoutedEventArgs args = new QueryHelpTextRoutedEventArgs( - AutomationQueryEvents.QueryHelpTextForGroupEvent, m_uiGroupOwner ); - - m_uiGroupOwner.DataGridContext.DataGridControl.RaiseEvent( args ); - - string helpText = null; - - if( args.Handled ) - helpText = args.HelpText; - - return ( helpText ?? string.Empty ); - } - - protected override string GetItemStatusCore() - { - QueryItemStatusRoutedEventArgs args = new QueryItemStatusRoutedEventArgs( - AutomationQueryEvents.QueryItemStatusForGroupEvent, m_uiGroupOwner ); - - m_uiGroupOwner.DataGridContext.DataGridControl.RaiseEvent( args ); - - string itemStatus = null; - - if( args.Handled ) - itemStatus = args.ItemStatus; - - return ( itemStatus ?? string.Empty ); - } - - protected override string GetItemTypeCore() - { - QueryItemTypeRoutedEventArgs args = new QueryItemTypeRoutedEventArgs( - AutomationQueryEvents.QueryItemTypeForGroupEvent, m_uiGroupOwner ); - - m_uiGroupOwner.DataGridContext.DataGridControl.RaiseEvent( args ); - - string itemType = null; - - if( args.Handled ) - itemType = args.ItemType; - - return ( itemType ?? string.Empty ); - } - - protected override AutomationPeer GetLabeledByCore() - { - return null; - } - - protected override string GetNameCore() - { - QueryNameRoutedEventArgs args = new QueryNameRoutedEventArgs( - AutomationQueryEvents.QueryNameForGroupEvent, m_uiGroupOwner ); - - m_uiGroupOwner.DataGridContext.DataGridControl.RaiseEvent( args ); - - string name = null; - - if( args.Handled ) - name = args.Name; - - return ( name ?? string.Empty ); - } - - protected override AutomationOrientation GetOrientationCore() - { - return AutomationOrientation.None; - } - - protected override bool HasKeyboardFocusCore() - { - return false; - } - - protected override bool IsContentElementCore() - { - return true; - } - - protected override bool IsControlElementCore() - { - return true; - } - - protected override bool IsEnabledCore() - { - return true; - } - - protected override bool IsKeyboardFocusableCore() - { - return false; - } - - protected override bool IsOffscreenCore() - { - return false; - } - - protected override bool IsPasswordCore() - { - return false; - } - - protected override bool IsRequiredForFormCore() - { - return false; - } - - protected override void SetFocusCore() - { - throw new NotSupportedException(); - } - - private void OnOwnerPropertyChanged( object sender, PropertyChangedEventArgs e ) - { - if( !AutomationPeer.ListenerExists( AutomationEvents.PropertyChanged ) ) - return; - - Debug.Assert( sender == this.Owner ); - - if( string.IsNullOrEmpty( e.PropertyName ) || ( e.PropertyName == DataGridGroupAutomationPeer.GroupIsExpandedPropertyName ) ) - { - if( this.Owner.IsExpanded ) - { - this.RaisePropertyChangedEvent( ExpandCollapsePatternIdentifiers.ExpandCollapseStateProperty, ExpandCollapseState.Collapsed, ExpandCollapseState.Expanded ); - } - else - { - this.RaisePropertyChangedEvent( ExpandCollapsePatternIdentifiers.ExpandCollapseStateProperty, ExpandCollapseState.Expanded, ExpandCollapseState.Collapsed ); - } - } - } - - internal static void AddHeaderPeer( - DataGridContext dataGridContext, - HeadersFootersGeneratorNode node, - List list, - Hashtable children, - Hashtable oldChildren ) - { - int headersCount = node.ItemCount; - - for( int i = 0; i < headersCount; i++ ) - { - // We use GetAt since it does not return the same thing as .Items. - // We need to get a GroupHeaderFooterItem. - object item = node.GetAt( i ); - - if( item != null ) - { - HeaderFooterItemAutomationPeer automationPeer = - oldChildren[ item ] as HeaderFooterItemAutomationPeer; - - if( automationPeer == null ) - { - automationPeer = new HeaderFooterItemAutomationPeer( dataGridContext, item ); - } - - Debug.Assert( automationPeer != null ); - - // we set ExtraInfo even if the header was already created since the position can change. - automationPeer.SetExtraInfo( HeaderFooterItemAutomationPeer.HeaderFooterType.Header, i ); - - // Force EventsSource to be updated - automationPeer.GetWrapperPeer(); - - list.Add( automationPeer ); - children[ item ] = automationPeer; - } - } - } - - internal static void AddFooterPeer( - DataGridContext dataGridContext, - HeadersFootersGeneratorNode node, - List list, - Hashtable children, - Hashtable oldChildren ) - { - int headersCount = node.ItemCount; - - for( int i = 0; i < headersCount; i++ ) - { - // We use GetAt since it does not return the same thing as .Items. - // We need to get a GroupHeaderFooterItem. - object item = node.GetAt( i ); - - if( item != null ) - { - HeaderFooterItemAutomationPeer automationPeer = - oldChildren[ item ] as HeaderFooterItemAutomationPeer; - - if( automationPeer == null ) - { - automationPeer = new HeaderFooterItemAutomationPeer( dataGridContext, item ); - } - - Debug.Assert( automationPeer != null ); - - // we set ExtraInfo even if the header was already created since the position can change. - automationPeer.SetExtraInfo( HeaderFooterItemAutomationPeer.HeaderFooterType.Footer, i ); - - // Force EventsSource to be updated - automationPeer.GetWrapperPeer(); - - list.Add( automationPeer ); - children[ item ] = automationPeer; - } - } - } - - #region IExpandCollapseProvider Members - - void IExpandCollapseProvider.Collapse() - { - m_uiGroupOwner.IsExpanded = false; - } - - void IExpandCollapseProvider.Expand() - { - m_uiGroupOwner.IsExpanded = true; - } - - ExpandCollapseState IExpandCollapseProvider.ExpandCollapseState - { - get - { - return ( m_uiGroupOwner.IsExpanded ) ? - ExpandCollapseState.Expanded : ExpandCollapseState.Collapsed; - } - } - - #endregion - - #region IItemContainerProvider Members - - public IRawElementProviderSimple FindItemByProperty( IRawElementProviderSimple startAfter, int propertyId, object value ) - { - if( ( propertyId != 0 ) && ( !DataGridGroupAutomationPeer.IsPropertySupportedForFindItem( propertyId ) ) ) - { - throw new ArgumentException( "Property not supported" ); - } - - Group owner = this.Owner; - GroupGeneratorNode generatorNode = owner.GeneratorNode; - - if( generatorNode == null ) - return null; - - DataGridContext dataGridContext = owner.DataGridContext; - - if( dataGridContext == null ) - return null; - - this.ResetChildrenCache(); - IList items = owner.GetItems(); - int itemsCount = ( items == null ) ? 0 : items.Count; - - DataGridItemAutomationPeer startAfterItemPeer = null; - HeaderFooterItemAutomationPeer startAfterHeaderFooterPeer = null; - - if( startAfter != null ) - { - AutomationPeer startAfterPeer = this.PeerFromProvider( startAfter ); - - if( startAfterPeer == null ) - return null; - - startAfterItemPeer = startAfterPeer as DataGridItemAutomationPeer; - startAfterHeaderFooterPeer = startAfterPeer as HeaderFooterItemAutomationPeer; - } - - int startIndex = 0; - - // Get header count - HeadersFootersGeneratorNode headerNode = generatorNode.GetHeaderNode(); - int headersCount = ( headerNode == null ) ? 0 : headerNode.ItemCount; - - // Get footer count - HeadersFootersGeneratorNode footerNode = generatorNode.GetFooterNode(); - int footersCount = ( footerNode == null ) ? 0 : footerNode.ItemCount; - - int childrenCount = headersCount + footersCount + itemsCount; - - if( startAfterItemPeer != null ) - { - startIndex = headersCount + startAfterItemPeer.Index + 1; - } - else if( startAfterHeaderFooterPeer != null ) - { - startIndex = startAfterHeaderFooterPeer.Index + 1; - - switch( startAfterHeaderFooterPeer.Type ) - { - case HeaderFooterItemAutomationPeer.HeaderFooterType.Header: - { - break; - } - case HeaderFooterItemAutomationPeer.HeaderFooterType.Footer: - { - startIndex += headersCount + itemsCount; - break; - } - } - } - - if( propertyId == 0 ) - { - AutomationPeer peer = this.GetPeerForChildrenIndex( startIndex ); - - if( peer == null ) - return null; - - return this.ProviderFromPeer( peer ); - } - - object propertyValue = null; - - for( int i = startIndex; i < childrenCount; i++ ) - { - AutomationPeer peer = this.GetPeerForChildrenIndex( i ); - - if( peer != null ) - { - try - { - propertyValue = peer.GetPropertyValue( propertyId ); - } - catch( Exception exception ) - { - if( exception is ElementNotAvailableException ) - { - continue; - } - } - - if( object.Equals( value, propertyValue ) ) - { - return this.ProviderFromPeer( peer ); - } - } - } - - return null; - } - - private AutomationPeer GetPeerForChildrenIndex( int index ) - { - Group owner = this.Owner; - GroupGeneratorNode generatorNode = owner.GeneratorNode; - - if( generatorNode == null ) - return null; - - DataGridContext dataGridContext = owner.DataGridContext; - - if( dataGridContext == null ) - return null; - - DataGridContextAutomationPeer dataGridContextAutomationPeer = dataGridContext.Peer; - HeadersFootersGeneratorNode headerNode = generatorNode.GetHeaderNode(); - int headersCount = ( headerNode == null ) ? 0 : headerNode.ItemCount; - - if( index < headersCount ) - { - object item = headerNode.GetAt( index ); - AutomationPeer automationPeer = m_headerFooterChildren[ item ] as AutomationPeer; - Debug.Assert( automationPeer != null ); - return automationPeer; - } - else - { - index -= headersCount; - IList items = owner.GetItems(); - int itemsCount = ( items == null ) ? 0 : items.Count; - - if( index < itemsCount ) - { - return dataGridContextAutomationPeer.FindOrCreateItemAutomationPeer( items[ index ], -1 ); - } - else - { - index -= itemsCount; - HeadersFootersGeneratorNode footerNode = generatorNode.GetFooterNode(); - int footersCount = ( footerNode == null ) ? 0 : footerNode.ItemCount; - - if( index < footersCount ) - { - object item = footerNode.GetAt( index ); - AutomationPeer automationPeer = m_headerFooterChildren[ item ] as AutomationPeer; - Debug.Assert( automationPeer != null ); - return automationPeer; - } - } - } - - return null; - } - - private static bool IsPropertySupportedForFindItem( int id ) - { - return ( ( AutomationElementIdentifiers.NameProperty.Id == id ) - || ( AutomationElementIdentifiers.AutomationIdProperty.Id == id ) - || ( AutomationElementIdentifiers.ControlTypeProperty.Id == id ) - || ( SelectionItemPatternIdentifiers.IsSelectedProperty.Id == id ) ); - } - - #endregion - - #region IWeakEventListener Members - - bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) - { - if( typeof( PropertyChangedEventManager ) == managerType ) - { - if( sender == this.Owner ) - { - this.OnOwnerPropertyChanged( sender, ( PropertyChangedEventArgs )e ); - } - - return true; - } - - return false; - } - - #endregion - - #region Private Fields - - private Hashtable m_dataChildren; - private Hashtable m_headerFooterChildren; - - #endregion - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/DataGridItemAutomationPeer.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/DataGridItemAutomationPeer.cs deleted file mode 100644 index 2aa31081..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/DataGridItemAutomationPeer.cs +++ /dev/null @@ -1,561 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; -using System.Windows.Automation.Peers; -using System.Windows.Automation.Provider; -using System.Windows.Controls; -using System.Windows.Automation; -using System.Collections; -using System.Collections.ObjectModel; -using System.Globalization; -using System.Windows.Data; -using System.Windows.Controls.Primitives; -using System.Windows.Threading; - -namespace Xceed.Wpf.DataGrid.Automation -{ - public class DataGridItemAutomationPeer : AutomationPeer, ISelectionItemProvider, IVirtualizedItemProvider, IScrollItemProvider - { - public DataGridItemAutomationPeer( object item, DataGridContext dataGridContext, int index ) - { - // if index = -1, it will be calculated later calling indexof on dataGridContext.Items. - - if( dataGridContext == null ) - throw new ArgumentNullException( "dataGridContext" ); - - m_item = item; - m_dataGridContext = dataGridContext; - m_index = index; - m_dataChildren = new Hashtable( 0 ); - } - - #region Item Property - - public object Item - { - get - { - return m_item; - } - } - - #endregion - - #region DataGridContext Property - - public DataGridContext DataGridContext - { - get - { - return m_dataGridContext; - } - } - - #endregion - - #region Index Property - - internal int Index - { - get - { - if( m_index == -1 ) - m_index = m_dataGridContext.Items.IndexOf( m_item ); - - return m_index; - } - } - - internal void SetIndex( int value ) - { - m_index = value; - } - - #endregion - - public override object GetPattern( PatternInterface patternInterface ) - { - if( ( patternInterface == PatternInterface.SelectionItem ) - || ( patternInterface == PatternInterface.VirtualizedItem ) - || ( patternInterface == PatternInterface.ScrollItem ) ) - { - return this; - } - - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetPattern( patternInterface ); - - return null; - } - - protected override AutomationControlType GetAutomationControlTypeCore() - { - return AutomationControlType.DataItem; - } - - protected override string GetClassNameCore() - { - return "DataRow"; - } - - protected override string GetAcceleratorKeyCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetAcceleratorKey(); - - return string.Empty; - } - - protected override string GetAccessKeyCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetAccessKey(); - - return string.Empty; - } - - protected override string GetAutomationIdCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - string automationId = null; - - if( wrapperPeer != null ) - automationId = wrapperPeer.GetAutomationId(); - - if( !string.IsNullOrEmpty( automationId ) ) - return automationId; - - return "Row_" + this.Index.ToString( CultureInfo.InvariantCulture ); - } - - protected override Rect GetBoundingRectangleCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetBoundingRectangle(); - - return new Rect(); - } - - protected override List GetChildrenCore() - { - DataRow dataRow = m_dataGridContext.CustomItemContainerGenerator.ContainerFromItem( m_item ) as DataRow; - - if( dataRow == null ) - return null; - - // Get child context ( Detail ) - DetailConfigurationCollection detailConfigurations = m_dataGridContext.DetailConfigurations; - int detailConfigurationsCount = detailConfigurations.Count; - - ReadOnlyObservableCollection visibleColumns = m_dataGridContext.VisibleColumns; - int visibleColumnsCount = visibleColumns.Count; - - if( visibleColumnsCount + detailConfigurationsCount <= 0 ) - return null; - - Hashtable oldDataChildren = m_dataChildren; - List list = new List( visibleColumnsCount + detailConfigurationsCount ); - m_dataChildren = new Hashtable( visibleColumnsCount + detailConfigurationsCount ); - - for( int i = 0; i < visibleColumnsCount; i++ ) - { - ColumnBase column = visibleColumns[ i ]; - - DataGridItemCellAutomationPeer cellAutomationPeer = - oldDataChildren[ column ] as DataGridItemCellAutomationPeer; - - if( cellAutomationPeer == null ) - cellAutomationPeer = new DataGridItemCellAutomationPeer( this, column ); - - // Always resetting the ColumnIndex since the visible position can have changed - cellAutomationPeer.ColumnIndex = i; - - list.Add( cellAutomationPeer ); - m_dataChildren[ column ] = cellAutomationPeer; - } - - for( int i = 0; i < detailConfigurationsCount; i++ ) - { - DetailConfiguration detailConfiguration = detailConfigurations[ i ]; - DataGridContextAutomationPeer detailDataGridContextAutomationPeer = null; - - detailDataGridContextAutomationPeer = - oldDataChildren[ detailConfiguration ] as DataGridContextAutomationPeer; - - if( detailDataGridContextAutomationPeer == null ) - { - detailDataGridContextAutomationPeer = new DataGridContextAutomationPeer( - m_dataGridContext.DataGridControl, m_dataGridContext, m_item, detailConfiguration ); - } - - list.Add( detailDataGridContextAutomationPeer ); - m_dataChildren[ detailConfiguration ] = detailDataGridContextAutomationPeer; - } - - return list; - } - - protected override Point GetClickablePointCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetClickablePoint(); - - return new Point( double.NaN, double.NaN ); - } - - protected override string GetHelpTextCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetHelpText(); - - return string.Empty; - } - - protected override string GetItemStatusCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetItemStatus(); - - return string.Empty; - } - - protected override string GetItemTypeCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetItemType(); - - return string.Empty; - } - - protected override AutomationPeer GetLabeledByCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetLabeledBy(); - - return null; - } - - protected override string GetNameCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - string name = null; - - if( wrapperPeer != null ) - name = wrapperPeer.GetName(); - - if( ( name == null ) && ( m_item is string ) ) - name = ( string )m_item; - - if( !string.IsNullOrEmpty( name ) ) - return name; - - Column mainColumn = this.DataGridContext.Columns.MainColumn as Column; - - if( ( mainColumn == null ) || ( !mainColumn.Visible ) ) - return string.Empty; - - BindingPathValueExtractor valueExtractor = this.DataGridContext.GetBindingPathExtractorForColumn( mainColumn, m_item ); - object mainColumnValue = valueExtractor.GetValueFromItem( m_item ); - - if( mainColumnValue == null ) - return string.Empty; - - return string.Format( CultureInfo.CurrentCulture, "{0}", mainColumnValue ); - } - - protected override AutomationOrientation GetOrientationCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetOrientation(); - - return AutomationOrientation.None; - } - - protected override bool HasKeyboardFocusCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - return ( ( wrapperPeer != null ) && ( wrapperPeer.HasKeyboardFocus() ) ); - } - - protected override bool IsContentElementCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.IsContentElement(); - - return true; - } - - protected override bool IsControlElementCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.IsControlElement(); - - return true; - } - - protected override bool IsEnabledCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - return ( ( wrapperPeer == null ) || wrapperPeer.IsEnabled() ); - } - - protected override bool IsKeyboardFocusableCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - return ( ( wrapperPeer != null ) && wrapperPeer.IsKeyboardFocusable() ); - } - - protected override bool IsOffscreenCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.IsOffscreen(); - - return true; - } - - protected override bool IsPasswordCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - return ( ( wrapperPeer != null ) && ( wrapperPeer.IsPassword() ) ); - } - - protected override bool IsRequiredForFormCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - return ( ( wrapperPeer != null ) && ( wrapperPeer.IsRequiredForForm() ) ); - } - - protected override void SetFocusCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - wrapperPeer.SetFocus(); - } - - internal UIElement GetWrapper() - { - if( m_dataGridContext.DataGridControl.IsItemItsOwnContainer( m_item ) ) - return m_item as UIElement; - - return m_dataGridContext.CustomItemContainerGenerator.ContainerFromItem( m_item ) as UIElement; - } - - internal AutomationPeer GetWrapperPeer() - { - UIElement wrapper = this.GetWrapper(); - - if( wrapper == null ) - return null; - - AutomationPeer peer = UIElementAutomationPeer.CreatePeerForElement( wrapper ); - - if( peer != null ) - { - peer.EventsSource = this; - return peer; - } - - return null; - } - - internal DataGridItemCellAutomationPeer GetDataGridItemCellPeer( ColumnBase column ) - { - // Force the creation of the children caching (m_dataChildren). - this.GetChildren(); - - return m_dataChildren[ column ] as DataGridItemCellAutomationPeer; - } - - internal DataGridContextAutomationPeer GetDetailPeer( DetailConfiguration detailConfig ) - { - return m_dataChildren[ detailConfig ] as DataGridContextAutomationPeer; - } - - #region ISelectionItemProvider Members - - bool ISelectionItemProvider.IsSelected - { - get - { - return m_dataGridContext.SelectedItemsStore.Contains( this.Index ); - } - } - - IRawElementProviderSimple ISelectionItemProvider.SelectionContainer - { - get - { - return this.ProviderFromPeer( m_dataGridContext.PeerSource ); - } - } - - void ISelectionItemProvider.AddToSelection() - { - if( !this.IsEnabled() ) - throw new ElementNotEnabledException(); - - DataGridControl dataGridControl = m_dataGridContext.DataGridControl; - - if( ( dataGridControl.SelectionModeToUse == SelectionMode.Single ) && ( dataGridControl.SelectedItem != null ) - && ( dataGridControl.SelectedItem != this.Item ) ) - { - throw new InvalidOperationException( "An attempt was made to select more than 1 item." ); - } - - dataGridControl.SelectionChangerManager.Begin(); - - try - { - dataGridControl.SelectionChangerManager.SelectItems( - m_dataGridContext, - new SelectionRangeWithItems( this.Index, m_item ) ); - } - finally - { - dataGridControl.SelectionChangerManager.End( false, true, true ); - } - } - - void ISelectionItemProvider.RemoveFromSelection() - { - if( !base.IsEnabled() ) - throw new ElementNotEnabledException(); - - DataGridControl dataGridControl = m_dataGridContext.DataGridControl; - dataGridControl.SelectionChangerManager.Begin(); - - try - { - dataGridControl.SelectionChangerManager.UnselectItems( - m_dataGridContext, - new SelectionRangeWithItems( this.Index, m_item ) ); - } - finally - { - dataGridControl.SelectionChangerManager.End( false, true, true ); - } - } - - void ISelectionItemProvider.Select() - { - if( !this.IsEnabled() ) - throw new ElementNotEnabledException(); - - DataGridControl dataGridControl = m_dataGridContext.DataGridControl; - dataGridControl.SelectionChangerManager.Begin(); - - try - { - dataGridControl.SelectionChangerManager.SelectJustThisItem( m_dataGridContext, this.Index, m_item ); - } - finally - { - dataGridControl.SelectionChangerManager.End( false, true, true ); - } - } - - internal void RaiseAutomationIsSelectedChanged( bool isSelected ) - { - this.RaisePropertyChangedEvent( SelectionItemPatternIdentifiers.IsSelectedProperty, !isSelected, isSelected ); - } - - #endregion - - #region IVirtualizedItemProvider Members - - public void Realize() - { - this.ScrollIntoView(); - } - - #endregion - - #region IScrollItemProvider Members - - public void ScrollIntoView() - { - if( m_dataGridContext == null ) - return; - - DataGridControl dataGridControl = m_dataGridContext.DataGridControl; - - if( dataGridControl == null ) - return; - - if( m_dataGridContext.CustomItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated ) - { - dataGridControl.BringItemIntoViewHelper( m_dataGridContext, m_item ); - } - else - { - this.Dispatcher.BeginInvoke( DispatcherPriority.Loaded, new DispatcherOperationCallback( this.BringItemIntoViewHelper ), m_item ); - } - } - - private object BringItemIntoViewHelper( object item ) - { - if( m_dataGridContext == null ) - return null; - - DataGridControl dataGridControl = m_dataGridContext.DataGridControl; - - if( dataGridControl == null ) - return null; - - dataGridControl.BringItemIntoViewHelper( m_dataGridContext, item ); - return null; - } - - #endregion - - private Hashtable m_dataChildren; - private object m_item; - private int m_index; - private DataGridContext m_dataGridContext; - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/DataGridItemCellAutomationPeer.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/DataGridItemCellAutomationPeer.cs deleted file mode 100644 index 44a4c367..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/DataGridItemCellAutomationPeer.cs +++ /dev/null @@ -1,439 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; -using System.Windows.Automation.Peers; -using System.Windows.Automation.Provider; -using System.Windows.Controls; -using System.Windows.Automation; -using System.Collections; -using System.Collections.ObjectModel; -using System.Globalization; -using System.Diagnostics; - -namespace Xceed.Wpf.DataGrid.Automation -{ - internal class DataGridItemCellAutomationPeer : AutomationPeer, ITableItemProvider - { - public DataGridItemCellAutomationPeer( DataGridItemAutomationPeer itemAutomationPeer, ColumnBase column ) - { - - if( itemAutomationPeer == null ) - throw new ArgumentNullException( "itemAutomationPeer" ); - - if( column == null ) - throw new ArgumentNullException( "column" ); - - m_itemAutomationPeer = itemAutomationPeer; - m_column = column; - - // Call the GetWrapperPeer since it will force the events of the wrapped peer to be rerooted to us. - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - } - - #region ItemAutomationPeer Property - - public DataGridItemAutomationPeer ItemAutomationPeer - { - get - { - return m_itemAutomationPeer; - } - } - - #endregion - - #region Column Property - - public ColumnBase Column - { - get - { - return m_column; - } - } - - #endregion - - #region ColumnIndex Property - - internal int ColumnIndex - { - get; - set; - } - - #endregion - - public override object GetPattern( PatternInterface patternInterface ) - { - switch( patternInterface ) - { - case PatternInterface.GridItem: - case PatternInterface.TableItem: - return this; - } - - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetPattern( patternInterface ); - - return null; - } - - protected override AutomationControlType GetAutomationControlTypeCore() - { - return AutomationControlType.Pane; - } - - protected override string GetClassNameCore() - { - return "Cell"; - } - - protected override string GetAcceleratorKeyCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetAcceleratorKey(); - - return string.Empty; - } - - protected override string GetAccessKeyCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetAccessKey(); - - return string.Empty; - } - - protected override string GetAutomationIdCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - string automationId = null; - - if( wrapperPeer != null ) - automationId = wrapperPeer.GetAutomationId(); - - if( automationId == null ) - automationId = string.Empty; - - return automationId; - } - - protected override Rect GetBoundingRectangleCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetBoundingRectangle(); - - return new Rect(); - } - - protected override List GetChildrenCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetChildren(); - - return null; - } - - protected override Point GetClickablePointCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetClickablePoint(); - - return new Point( double.NaN, double.NaN ); - } - - protected override string GetHelpTextCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetHelpText(); - - return string.Empty; - } - - protected override string GetItemStatusCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetItemStatus(); - - return string.Empty; - } - - protected override string GetItemTypeCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetItemType(); - - return string.Empty; - } - - protected override AutomationPeer GetLabeledByCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetLabeledBy(); - - return null; - } - - protected override string GetNameCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - string name = null; - - if( wrapperPeer != null ) - name = wrapperPeer.GetName(); - - if( name == null ) - name = string.Empty; - - return name; - } - - protected override AutomationOrientation GetOrientationCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetOrientation(); - - return AutomationOrientation.None; - } - - protected override bool HasKeyboardFocusCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - return ( ( wrapperPeer != null ) && ( wrapperPeer.HasKeyboardFocus() ) ); - } - - protected override bool IsContentElementCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.IsContentElement(); - - return true; - } - - protected override bool IsControlElementCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.IsControlElement(); - - return true; - } - - protected override bool IsEnabledCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - return ( ( wrapperPeer == null ) || wrapperPeer.IsEnabled() ); - } - - protected override bool IsKeyboardFocusableCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - return ( ( wrapperPeer != null ) && wrapperPeer.IsKeyboardFocusable() ); - } - - protected override bool IsOffscreenCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.IsOffscreen(); - - return true; - } - - protected override bool IsPasswordCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - return ( ( wrapperPeer != null ) && ( wrapperPeer.IsPassword() ) ); - } - - protected override bool IsRequiredForFormCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - return ( ( wrapperPeer != null ) && ( wrapperPeer.IsRequiredForForm() ) ); - } - - protected override void SetFocusCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - wrapperPeer.SetFocus(); - } - - internal UIElement GetWrapper() - { - if( m_itemAutomationPeer == null ) - return null; - - Row row = m_itemAutomationPeer.GetWrapper() as Row; - - if( row == null ) - return null; - - return row.Cells[ m_column ]; - } - - internal AutomationPeer GetWrapperPeer() - { - UIElement wrapper = this.GetWrapper(); - - if( wrapper == null ) - return null; - - AutomationPeer peer = UIElementAutomationPeer.CreatePeerForElement( wrapper ); - - if( peer != null ) - { - peer.EventsSource = this; - return peer; - } - - return null; - } - - #region IGridItemProvider Members - - int IGridItemProvider.Column - { - get - { - return this.ColumnIndex; - } - } - - int IGridItemProvider.ColumnSpan - { - get - { - return 1; - } - } - - IRawElementProviderSimple IGridItemProvider.ContainingGrid - { - get - { - return this.ProviderFromPeer( this.ItemAutomationPeer.DataGridContext.PeerSource ); - } - } - - int IGridItemProvider.Row - { - get - { - return m_itemAutomationPeer.Index; - } - } - - int IGridItemProvider.RowSpan - { - get - { - return 1; - } - } - - #endregion - - #region ITableItemProvider Members - - IRawElementProviderSimple[] ITableItemProvider.GetColumnHeaderItems() - { - DataGridItemAutomationPeer dataGridItemAutomationPeer = m_itemAutomationPeer; - - if( dataGridItemAutomationPeer == null ) - return new IRawElementProviderSimple[ 0 ]; - - DataGridContext dataGridContext = dataGridItemAutomationPeer.DataGridContext; - - if( dataGridContext == null ) - return new IRawElementProviderSimple[ 0 ]; - - List headersFootersPeer = dataGridContext.Peer.GetColumnHeadersPeer(); - - if( headersFootersPeer == null ) - return new IRawElementProviderSimple[ 0 ]; - - int headersFootersPeerCount = headersFootersPeer.Count; - List rawElementProviderSimples = new List( headersFootersPeerCount ); - - for( int i = 0; i < headersFootersPeerCount; i++ ) - { - RowAutomationPeer rowPeer = headersFootersPeer[ i ] as RowAutomationPeer; - - if( rowPeer != null ) - { - Cell cell = rowPeer.Owner.Cells[ m_column ]; - - if( cell != null ) - { - AutomationPeer automationPeer = FrameworkElementAutomationPeer.CreatePeerForElement( cell ); - Debug.Assert( automationPeer != null ); - - if( automationPeer != null ) - { - rawElementProviderSimples.Add( this.ProviderFromPeer( automationPeer ) ); - } - } - } - } - - return rawElementProviderSimples.ToArray(); - } - - IRawElementProviderSimple[] ITableItemProvider.GetRowHeaderItems() - { - return new IRawElementProviderSimple[ 0 ]; - } - - #endregion ITableItemProvider Members - - private DataGridItemAutomationPeer m_itemAutomationPeer; - private ColumnBase m_column; - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/HeaderFooterItemAutomationPeer.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/HeaderFooterItemAutomationPeer.cs deleted file mode 100644 index 78ccef4c..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/HeaderFooterItemAutomationPeer.cs +++ /dev/null @@ -1,406 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.Linq; -using System.Windows; -using System.Windows.Automation.Peers; -using System.Windows.Automation.Provider; -using System.Windows.Controls.Primitives; -using System.Windows.Threading; - -namespace Xceed.Wpf.DataGrid.Automation -{ - internal class HeaderFooterItemAutomationPeer : AutomationPeer, IVirtualizedItemProvider, IScrollItemProvider - { - public HeaderFooterItemAutomationPeer( DataGridContext dataGridContext, object owner ) - { - if( dataGridContext == null ) - throw new ArgumentNullException( "dataGridContext" ); - - if( owner == null ) - throw new ArgumentNullException( "owner" ); - - Debug.Assert( ( owner is GroupHeaderFooterItem ) || ( owner is DataTemplate ) || ( owner is HeaderFooterItem ) ); - - m_owner = owner; - m_dataGridContext = dataGridContext; - } - - #region Owner Property - - public object Owner - { - get - { - return m_owner; - } - } - - #endregion - - #region Type Property - - internal HeaderFooterType Type - { - get - { - return m_headerFooterType; - } - } - - #endregion - - #region Index Property - - internal int Index - { - get - { - return m_index; - } - } - - #endregion - - public override object GetPattern( PatternInterface patternInterface ) - { - if( ( patternInterface == PatternInterface.VirtualizedItem ) - || ( patternInterface == PatternInterface.ScrollItem ) ) - { - return this; - } - - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetPattern( patternInterface ); - - return null; - } - - protected override AutomationControlType GetAutomationControlTypeCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetAutomationControlType(); - - return AutomationControlType.Custom; - } - - protected override string GetClassNameCore() - { - return "HeaderFooterItem"; - } - - protected override string GetAcceleratorKeyCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetAcceleratorKey(); - - return string.Empty; - } - - protected override string GetAccessKeyCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetAccessKey(); - - return string.Empty; - } - - protected override string GetAutomationIdCore() - { - switch( m_headerFooterType ) - { - case HeaderFooterType.FixedHeader: - return "FixedHeader_" + m_index.ToString( CultureInfo.InvariantCulture ); - - case HeaderFooterType.Header: - return "Header_" + m_index.ToString( CultureInfo.InvariantCulture ); - - case HeaderFooterType.FixedFooter: - return "FixedFooter_" + m_index.ToString( CultureInfo.InvariantCulture ); - - default: // HeaderFooterType.Footer - return "Footer_" + m_index.ToString( CultureInfo.InvariantCulture ); - } - } - - protected override Rect GetBoundingRectangleCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetBoundingRectangle(); - - return Rect.Empty; - } - - protected override List GetChildrenCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetChildren(); - - return null; - } - - protected override Point GetClickablePointCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetClickablePoint(); - - return new Point( double.NaN, double.NaN ); - } - - protected override string GetHelpTextCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetHelpText(); - - return string.Empty; - } - - protected override string GetItemStatusCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetItemStatus(); - - return string.Empty; - } - - protected override string GetItemTypeCore() - { - return string.Empty; - } - - protected override AutomationPeer GetLabeledByCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetLabeledBy(); - - return null; - } - - protected override string GetNameCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetName(); - - return string.Empty; - } - - protected override AutomationOrientation GetOrientationCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.GetOrientation(); - - return AutomationOrientation.None; - } - - protected override bool HasKeyboardFocusCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - return ( ( wrapperPeer != null ) && ( wrapperPeer.HasKeyboardFocus() ) ); - } - - protected override bool IsContentElementCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.IsContentElement(); - - return true; - } - - protected override bool IsControlElementCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.IsControlElement(); - - return true; - } - - protected override bool IsEnabledCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - return ( ( wrapperPeer == null ) || wrapperPeer.IsEnabled() ); - } - - protected override bool IsKeyboardFocusableCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - return ( ( wrapperPeer != null ) && wrapperPeer.IsKeyboardFocusable() ); - } - - protected override bool IsOffscreenCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - return wrapperPeer.IsOffscreen(); - - return true; - } - - protected override bool IsPasswordCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - return ( ( wrapperPeer != null ) && ( wrapperPeer.IsPassword() ) ); - } - - protected override bool IsRequiredForFormCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - return ( ( wrapperPeer != null ) && ( wrapperPeer.IsRequiredForForm() ) ); - } - - protected override void SetFocusCore() - { - AutomationPeer wrapperPeer = this.GetWrapperPeer(); - - if( wrapperPeer != null ) - wrapperPeer.SetFocus(); - } - - internal void SetExtraInfo( HeaderFooterType headerFooterType, int index ) - { - m_headerFooterType = headerFooterType; - m_index = index; - } - - internal UIElement GetWrapper() - { - HeaderFooterItem headerFooterItem = m_owner as HeaderFooterItem; - if( headerFooterItem == null ) - { - headerFooterItem = m_dataGridContext.GetContainerFromItem( m_owner ) as HeaderFooterItem; - } - - if( headerFooterItem == null ) - return null; - - var container = headerFooterItem.GetTemplatedDescendantDataGridItemContainers().FirstOrDefault(); - if( container != null ) - return container as UIElement; - - return headerFooterItem; - } - - internal AutomationPeer GetWrapperPeer() - { - UIElement wrapper = this.GetWrapper(); - - if( wrapper == null ) - return null; - - AutomationPeer peer = UIElementAutomationPeer.CreatePeerForElement( wrapper ); - - if( peer != null ) - { - peer.EventsSource = this; - return peer; - } - - return null; - } - - #region IVirtualizedItemProvider Members - - public void Realize() - { - this.ScrollIntoView(); - } - - #endregion - - #region IScrollItemProvider Members - - public void ScrollIntoView() - { - if( m_dataGridContext == null ) - return; - - DataGridControl dataGridControl = m_dataGridContext.DataGridControl; - - if( dataGridControl == null ) - return; - - if( m_dataGridContext.CustomItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated ) - { - dataGridControl.BringItemIntoViewHelper( m_dataGridContext, m_owner ); - } - else - { - this.Dispatcher.BeginInvoke( DispatcherPriority.Loaded, new DispatcherOperationCallback( this.BringItemIntoViewHelper ), m_owner ); - } - } - - private object BringItemIntoViewHelper( object item ) - { - if( m_dataGridContext == null ) - return null; - - DataGridControl dataGridControl = m_dataGridContext.DataGridControl; - - if( dataGridControl == null ) - return null; - - dataGridControl.BringItemIntoViewHelper( m_dataGridContext, item ); - return null; - } - - #endregion - - private DataGridContext m_dataGridContext; - private object m_owner; - private HeaderFooterType m_headerFooterType; - private int m_index; - - public enum HeaderFooterType - { - FixedHeader, - Header, - Footer, - FixedFooter - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/QueryAutomationIdRoutedEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/QueryAutomationIdRoutedEventArgs.cs deleted file mode 100644 index 3885a042..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/QueryAutomationIdRoutedEventArgs.cs +++ /dev/null @@ -1,44 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid.Automation -{ - public delegate void QueryAutomationIdRoutedEventHandler( object sender, QueryAutomationIdRoutedEventArgs e ); - - public class QueryAutomationIdRoutedEventArgs : RoutedEventArgs - { - public QueryAutomationIdRoutedEventArgs( RoutedEvent routedEvent, object source ) - : base( routedEvent, source ) - { - } - - #region AutomationId Property - - public string AutomationId - { - get; - set; - } - - #endregion - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/QueryItemTypeRoutedEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/QueryItemTypeRoutedEventArgs.cs deleted file mode 100644 index 62250112..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/QueryItemTypeRoutedEventArgs.cs +++ /dev/null @@ -1,44 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid.Automation -{ - public delegate void QueryItemTypeRoutedEventHandler( object sender, QueryItemTypeRoutedEventArgs e ); - - public class QueryItemTypeRoutedEventArgs : RoutedEventArgs - { - public QueryItemTypeRoutedEventArgs( RoutedEvent routedEvent, object source ) - : base( routedEvent, source ) - { - } - - #region ItemType Property - - public string ItemType - { - get; - set; - } - - #endregion - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/QueryNameRoutedEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/QueryNameRoutedEventArgs.cs deleted file mode 100644 index cb13e8a6..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/QueryNameRoutedEventArgs.cs +++ /dev/null @@ -1,44 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid.Automation -{ - public delegate void QueryNameRoutedEventHandler( object sender, QueryNameRoutedEventArgs e ); - - public class QueryNameRoutedEventArgs : RoutedEventArgs - { - public QueryNameRoutedEventArgs( RoutedEvent routedEvent, object source ) - : base( routedEvent, source ) - { - } - - #region Name Property - - public string Name - { - get; - set; - } - - #endregion - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/RowAutomationPeer.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/RowAutomationPeer.cs deleted file mode 100644 index 0956bc76..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Automation/RowAutomationPeer.cs +++ /dev/null @@ -1,49 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Automation.Peers; - -namespace Xceed.Wpf.DataGrid.Automation -{ - public class RowAutomationPeer : FrameworkElementAutomationPeer - { - public RowAutomationPeer( Row owner ) - : base( owner ) - { - } - - #region Owner Property - - public new Row Owner - { - get - { - return base.Owner as Row; - } - } - - #endregion - - protected override AutomationControlType GetAutomationControlTypeCore() - { - return AutomationControlType.Pane; - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/BindingProxy.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/BindingProxy.cs new file mode 100644 index 00000000..d8d3dd82 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/BindingProxy.cs @@ -0,0 +1,60 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System.ComponentModel; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + [Browsable( false )] + [EditorBrowsable( EditorBrowsableState.Never )] + public class BindingProxy : Freezable + { + #region Value Property + + public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( + "Value", + typeof( object ), + typeof( BindingProxy ), + new UIPropertyMetadata( null ) ); + + public object Value + { + get + { + return this.GetValue( BindingProxy.ValueProperty ); + } + set + { + this.SetValue( BindingProxy.ValueProperty, value ); + } + } + + #endregion + + protected override Freezable CreateInstanceCore() + { + return new BindingProxy(); + } + + protected sealed override bool FreezeCore( bool isChecking ) + { + // Only derived from Freezable to have DataContext and ElementName binding. + // So we don't want to be freezable. + return false; + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CanBeCurrentWhenReadOnlyChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CanBeCurrentWhenReadOnlyChangedEventManager.cs deleted file mode 100644 index 0171d10a..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CanBeCurrentWhenReadOnlyChangedEventManager.cs +++ /dev/null @@ -1,74 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class CanBeCurrentWhenReadOnlyChangedEventManager: WeakEventManager - { - private CanBeCurrentWhenReadOnlyChangedEventManager() - { - } - - public static void AddListener( ColumnBase source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( ColumnBase source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - ColumnBase column = ( ColumnBase )source; - column.CanBeCurrentWhenReadOnlyChanged += new EventHandler( this.OnCanBeCurrentWhenReadOnlyChanged ); - } - - protected override void StopListening( object source ) - { - ColumnBase column = ( ColumnBase )source; - column.CanBeCurrentWhenReadOnlyChanged -= new EventHandler( this.OnCanBeCurrentWhenReadOnlyChanged ); - } - - private static CanBeCurrentWhenReadOnlyChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( CanBeCurrentWhenReadOnlyChangedEventManager ); - CanBeCurrentWhenReadOnlyChangedEventManager currentManager = ( CanBeCurrentWhenReadOnlyChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new CanBeCurrentWhenReadOnlyChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnCanBeCurrentWhenReadOnlyChanged( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Cell.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Cell.cs index f739c00b..64490444 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Cell.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Cell.cs @@ -32,7 +32,7 @@ using System.Windows.Input; using System.Windows.Media; using System.Windows.Threading; using Xceed.Utils.Wpf; -using Xceed.Wpf.DataGrid.Automation; +using Xceed.Wpf.DataGrid.Utils; using Xceed.Wpf.DataGrid.ValidationRules; using Xceed.Wpf.DataGrid.Views; using Xceed.Wpf.Toolkit.Core; @@ -42,6 +42,8 @@ namespace Xceed.Wpf.DataGrid [TemplatePart( Name = "PART_CellContentPresenter", Type = typeof( ContentPresenter ) )] public class Cell : ContentControl, INotifyPropertyChanged, IWeakEventListener { + internal static readonly string FieldNamePropertyName = PropertyHelper.GetPropertyName( ( Cell c ) => c.FieldName ); + // This validation rule is meant to be used as the rule in error set in a Cell's ValidationError when the CellEditor's HasError attached property returns true. private static readonly CellEditorErrorValidationRule CellEditorErrorValidationRule = new CellEditorErrorValidationRule(); @@ -53,9 +55,7 @@ namespace Xceed.Wpf.DataGrid static Cell() { Cell.ContentProperty.OverrideMetadata( typeof( Cell ), - new FrameworkPropertyMetadata( - new PropertyChangedCallback( OnContentChanged ), - new CoerceValueCallback( OnCoerceContent ) ) ); + new FrameworkPropertyMetadata( new PropertyChangedCallback( OnContentChanged ), new CoerceValueCallback( OnCoerceContent ) ) ); //This configures the TAB key to go trough the controls of the cell once... then continue with other controls KeyboardNavigation.TabNavigationProperty.OverrideMetadata( typeof( Cell ), new FrameworkPropertyMetadata( KeyboardNavigationMode.None ) ); @@ -84,7 +84,6 @@ namespace Xceed.Wpf.DataGrid Cell.IsBeingEditedProperty = Cell.IsBeingEditedPropertyKey.DependencyProperty; Cell.IsDirtyProperty = Cell.IsDirtyPropertyKey.DependencyProperty; - Cell.IsDirtyFromInitializingInsertionRowProperty = Cell.IsDirtyFromInitializingInsertionRowPropertyKey.DependencyProperty; // We do this last to ensure all the Static content of the cell is done before using // any static read-only field of the row. @@ -135,8 +134,8 @@ namespace Xceed.Wpf.DataGrid // Remove the error template by default. this.SetValue( Validation.ErrorTemplateProperty, null ); - Validation.AddErrorHandler( this, Cell.ContentBinding_ValidationError ); - this.TargetUpdated += new EventHandler( this.ContentBinding_TargetUpdated ); + Validation.AddErrorHandler( this, Cell.OnContentBindingNotifyValidationError ); + this.TargetUpdated += new EventHandler( this.OnContentBindingTargetUpdated ); this.LayoutUpdated += new EventHandler( this.Cell_LayoutUpdated ); } @@ -282,19 +281,19 @@ namespace Xceed.Wpf.DataGrid cellState.SetIsBeingEdited( value ); } - if( !this.ParentRow.IsClearingContainer ) - { - //If cell is being edited - if( value ) - { - //Raise the RoutedEvent that notifies any Row that the cell is being edited. - RoutedEventArgs eventArgs = new RoutedEventArgs( Cell.IsBeingEditedEvent ); - this.RaiseEvent( eventArgs ); - this.FocusEditor = true; - } + if( this.ParentRow.IsClearingContainer ) + return; - this.RefreshDisplayedTemplate(); + //If cell is being edited + if( value ) + { + //Raise the RoutedEvent that notifies any Row that the cell is being edited. + RoutedEventArgs eventArgs = new RoutedEventArgs( Cell.IsBeingEditedEvent ); + this.RaiseEvent( eventArgs ); + this.FocusEditor = true; } + + this.RefreshDisplayedTemplate(); } } @@ -344,41 +343,6 @@ namespace Xceed.Wpf.DataGrid #endregion IsDirty Read-Only Property - #region IsDirtyFromInitializingInsertionRow Read-Only Property - - private static readonly DependencyPropertyKey IsDirtyFromInitializingInsertionRowPropertyKey = DependencyProperty.RegisterReadOnly( - "IsDirtyFromInitializingInsertionRow", - typeof( bool ), - typeof( Cell ), - new PropertyMetadata( false ) ); - - internal static readonly DependencyProperty IsDirtyFromInitializingInsertionRowProperty; - - internal bool IsDirtyFromInitializingInsertionRow - { - get - { - return ( bool )this.GetValue( Cell.IsDirtyFromInitializingInsertionRowProperty ); - } - } - - internal void SetIsDirtyFromInitializingInsertionRow( bool value ) - { - if( value != this.IsDirtyFromInitializingInsertionRow ) - { - if( value ) - { - this.SetValue( Cell.IsDirtyFromInitializingInsertionRowPropertyKey, value ); - } - else - { - this.SetValue( Cell.IsDirtyFromInitializingInsertionRowPropertyKey, DependencyProperty.UnsetValue ); - } - } - } - - #endregion IsDirtyFromInitializingInsertionRow Read-Only Property - #region IsCellEditorDisplayed Read-Only Property public bool IsCellEditorDisplayed @@ -402,8 +366,8 @@ namespace Xceed.Wpf.DataGrid #region CurrentBackground Property - public static readonly DependencyProperty CurrentBackgroundProperty = - DependencyProperty.Register( "CurrentBackground", + public static readonly DependencyProperty CurrentBackgroundProperty = DependencyProperty.Register( + "CurrentBackground", typeof( Brush ), typeof( Cell ), new FrameworkPropertyMetadata( null ) ); @@ -463,8 +427,7 @@ namespace Xceed.Wpf.DataGrid #region CellErrorStyle Property - public static readonly DependencyProperty CellErrorStyleProperty = - DataGridControl.CellErrorStyleProperty.AddOwner( typeof( Cell ) ); + public static readonly DependencyProperty CellErrorStyleProperty = DataGridControl.CellErrorStyleProperty.AddOwner( typeof( Cell ) ); public Style CellErrorStyle { @@ -483,17 +446,13 @@ namespace Xceed.Wpf.DataGrid #region HasValidationError Read-Only Property - private static readonly DependencyPropertyKey HasValidationErrorPropertyKey = - DependencyProperty.RegisterReadOnly( + private static readonly DependencyPropertyKey HasValidationErrorPropertyKey = DependencyProperty.RegisterReadOnly( "HasValidationError", typeof( bool ), typeof( Cell ), - new UIPropertyMetadata( - false, - new PropertyChangedCallback( Cell.OnHasValidationErrorChanged ) ) ); + new UIPropertyMetadata( false, new PropertyChangedCallback( Cell.OnHasValidationErrorChanged ) ) ); - public static readonly DependencyProperty HasValidationErrorProperty = - HasValidationErrorPropertyKey.DependencyProperty; + public static readonly DependencyProperty HasValidationErrorProperty = HasValidationErrorPropertyKey.DependencyProperty; public bool HasValidationError { @@ -523,13 +482,12 @@ namespace Xceed.Wpf.DataGrid Cell cell = ( Cell )sender; // If we are in the process of clearing the cell, don't refresh the error style. - // It is imperative to take care of resetting all the flags used by the DelayedRefreshErrorStyle architecture in the - // Cell's ClearContainer method though. - if( ( cell.ParentRow != null ) && ( cell.ParentRow.IsClearingContainer ) ) + // It is imperative to take care of resetting all the flags used by the DelayedRefreshErrorStyle architecture in the Cell's ClearContainer method though. + var parentRow = cell.ParentRow; + if( ( parentRow != null ) && parentRow.IsClearingContainer ) return; - // This flag is used to optimize the synchronization of error flags on the parent row/column so that - // it is done only once at the end of the UpdateHasErrorFlags method. + // This flag is used to optimize the synchronization of error flags on the parent row/column so that it is done only once at the end of the UpdateHasErrorFlags method. cell.HasPendingSyncParentErrorFlags = true; if( cell.HasPendingErrorStyleRefresh ) @@ -575,7 +533,7 @@ namespace Xceed.Wpf.DataGrid { m_delayedRefreshErrorStyleDispatcherOperation = null; System.Diagnostics.Debug.Assert( this.HasPendingErrorStyleRefresh, "The operation should have been aborted." ); - System.Diagnostics.Debug.Assert( ( this.ParentRow != null ) && ( !this.ParentRow.IsClearingContainer ), "The operation should have been aborted." ); + System.Diagnostics.Debug.Assert( ( ( this.ParentRow != null ) && !this.ParentRow.IsClearingContainer ), "The operation should have been aborted." ); if( !this.IsLoaded ) { @@ -641,8 +599,7 @@ namespace Xceed.Wpf.DataGrid typeof( Cell ), new PropertyMetadata( false ) ); - public static readonly DependencyProperty IsValidationErrorRestrictiveProperty = - Cell.IsValidationErrorRestrictivePropertyKey.DependencyProperty; + public static readonly DependencyProperty IsValidationErrorRestrictiveProperty = Cell.IsValidationErrorRestrictivePropertyKey.DependencyProperty; public bool IsValidationErrorRestrictive { @@ -677,7 +634,8 @@ namespace Xceed.Wpf.DataGrid #region ValidationError Read-Only Property - public static readonly RoutedEvent ValidationErrorChangingEvent = EventManager.RegisterRoutedEvent( "ValidationErrorChanging", RoutingStrategy.Bubble, typeof( CellValidationErrorRoutedEventHandler ), typeof( Cell ) ); + public static readonly RoutedEvent ValidationErrorChangingEvent = + EventManager.RegisterRoutedEvent( "ValidationErrorChanging", RoutingStrategy.Bubble, typeof( CellValidationErrorRoutedEventHandler ), typeof( Cell ) ); public event CellValidationErrorRoutedEventHandler ValidationErrorChanging { @@ -696,15 +654,13 @@ namespace Xceed.Wpf.DataGrid this.RaiseEvent( e ); } - private static readonly DependencyPropertyKey ValidationErrorPropertyKey = - DependencyProperty.RegisterReadOnly( "ValidationError", typeof( CellValidationError ), typeof( Cell ), - new FrameworkPropertyMetadata( - null, - new PropertyChangedCallback( Cell.OnValidationErrorChanged ), - new CoerceValueCallback( Cell.OnCoerceValidationError ) ) ); + private static readonly DependencyPropertyKey ValidationErrorPropertyKey = DependencyProperty.RegisterReadOnly( + "ValidationError", + typeof( CellValidationError ), + typeof( Cell ), + new FrameworkPropertyMetadata( null, new PropertyChangedCallback( Cell.OnValidationErrorChanged ), new CoerceValueCallback( Cell.OnCoerceValidationError ) ) ); - public static readonly DependencyProperty ValidationErrorProperty = - ValidationErrorPropertyKey.DependencyProperty; + public static readonly DependencyProperty ValidationErrorProperty = ValidationErrorPropertyKey.DependencyProperty; public CellValidationError ValidationError { @@ -735,12 +691,10 @@ namespace Xceed.Wpf.DataGrid CellValidationError newCellValidationError = e.NewValue as CellValidationError; - // Update the flags telling us wether or not the current validation error is CellEditor error, or a UI error and - // update the HasValidationError dependency property. + // Update the flags telling us wether or not the current validation error is CellEditor error, or a UI error and update the HasValidationError dependency property. cell.UpdateHasErrorFlags( newCellValidationError ); - // Refresh which content template is displayed (editTemplate or not) in case there was a CellEditor validation error on the cell - // and now there isn't one anymore. + // Refresh which content template is displayed (editTemplate or not) in case there was a CellEditor validation error on the cell and now there isn't one anymore. cell.RefreshDisplayedTemplate(); } @@ -778,7 +732,9 @@ namespace Xceed.Wpf.DataGrid ColumnBase column = this.ParentColumn; if( column != null ) + { column.SetHasValidationError( hasValidationError ); + } Row row = this.ParentRow; @@ -810,7 +766,9 @@ namespace Xceed.Wpf.DataGrid CellState cellState = this.GetEditCachedState(); if( cellState != null ) + { cellState.SetCellValidationError( value ); + } } } @@ -824,9 +782,11 @@ namespace Xceed.Wpf.DataGrid #region CellDisplayEditorMatchingConditions Property - private static readonly DependencyProperty CellDisplayEditorMatchingConditionsProperty = - DependencyProperty.Register( "CellDisplayEditorMatchingConditions", typeof( CellEditorDisplayConditions ), typeof( Cell ), - new UIPropertyMetadata( CellEditorDisplayConditions.None, new PropertyChangedCallback( OnMatchingDisplayEditorChanged ) ) ); + private static readonly DependencyProperty CellDisplayEditorMatchingConditionsProperty = DependencyProperty.Register( + "CellDisplayEditorMatchingConditions", + typeof( CellEditorDisplayConditions ), + typeof( Cell ), + new UIPropertyMetadata( CellEditorDisplayConditions.None, new PropertyChangedCallback( OnMatchingDisplayEditorChanged ) ) ); internal void SetDisplayEditorMatchingCondition( CellEditorDisplayConditions condition ) { @@ -943,7 +903,9 @@ namespace Xceed.Wpf.DataGrid #region ParentCell Property private static readonly DependencyPropertyKey ParentCellPropertyKey = DependencyProperty.RegisterAttachedReadOnly( - "ParentCell", typeof( Cell ), typeof( Cell ), + "ParentCell", + typeof( Cell ), + typeof( Cell ), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.Inherits ) ); public static readonly DependencyProperty ParentCellProperty; @@ -961,7 +923,7 @@ namespace Xceed.Wpf.DataGrid "ParentColumn", typeof( ColumnBase ), typeof( Cell ), - new PropertyMetadata( null ) ); + new PropertyMetadata( null, new PropertyChangedCallback( Cell.OnParentColumnChanged ) ) ); public static readonly DependencyProperty ParentColumnProperty; @@ -971,55 +933,40 @@ namespace Xceed.Wpf.DataGrid { return ( ColumnBase )this.GetValue( Cell.ParentColumnProperty ); } + private set + { + this.SetValue( Cell.ParentColumnPropertyKey, value ); + } } - internal virtual void SetParentColumn( ColumnBase value ) + internal virtual void OnParentColumnChanged( ColumnBase oldColumn, ColumnBase newColumn ) { - if( value == null ) - throw new ArgumentNullException( "value" ); - - // There is nothing to do if the parent column is the same. - var parentColumn = this.ParentColumn; - if( value == parentColumn ) - return; - - // Unregister from the old Parent Column's event. - if( parentColumn != null ) + if( oldColumn != null ) { - CellEditorDisplayConditionsChangedEventManager.RemoveListener( parentColumn, this ); - CellContentTemplateChangedEventManager.RemoveListener( parentColumn, this ); - CanBeCurrentWhenReadOnlyChangedEventManager.RemoveListener( parentColumn, this ); - CellContentStringFormatChangedEventManager.RemoveListener( parentColumn, this ); + PropertyChangedEventManager.RemoveListener( oldColumn, this, string.Empty ); + } - var dataBoundParentColumn = parentColumn as Column; - if( dataBoundParentColumn != null ) - { - ForeignKeyConfigurationChangedEventManager.RemoveListener( dataBoundParentColumn, this ); - } + if( newColumn != null ) + { + PropertyChangedEventManager.AddListener( newColumn, this, string.Empty ); } - this.SetValue( Cell.ParentColumnPropertyKey, value ); - this.UpdateAnimatedColumnReorderingBindings( Row.GetIsTemplateCell( this ) ); + this.UpdateFocusable(); + } - Debug.Assert( value == this.ParentColumn ); + private static void OnParentColumnChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) + { + var self = sender as Cell; + if( self == null ) + return; - // Register to the new Parent Column's event. - if( value != null ) - { - CellEditorDisplayConditionsChangedEventManager.AddListener( value, this ); - CellContentTemplateChangedEventManager.AddListener( value, this ); - CanBeCurrentWhenReadOnlyChangedEventManager.AddListener( value, this ); - CellContentStringFormatChangedEventManager.AddListener( value, this ); + self.OnParentColumnChanged( ( ColumnBase )e.OldValue, ( ColumnBase )e.NewValue ); - var dataBoundParentColumn = value as Column; - if( dataBoundParentColumn != null ) - { - ForeignKeyConfigurationChangedEventManager.AddListener( dataBoundParentColumn, this ); - } - } + // Since Cell.FieldName in fact returns Cell.ParentColumn.FieldName, a PropertyChanged corresponding to FieldName must be raised when the ParentColumn has changed. + self.OnPropertyChanged( Cell.FieldNamePropertyName ); } - #endregion ParentColumn Read-Only Property + #endregion #region ParentRow Read-Only Property @@ -1037,17 +984,13 @@ namespace Xceed.Wpf.DataGrid { return ( Row )this.GetValue( Cell.ParentRowProperty ); } + private set + { + this.SetValue( Cell.ParentRowPropertyKey, value ); + } } - private void SetParentRow( Row value ) - { - if( value == null ) - throw new ArgumentNullException( "value" ); - - this.SetValue( Cell.ParentRowPropertyKey, value ); - } - - #endregion ParentRow Read-Only Property + #endregion #region FieldName Property @@ -1070,10 +1013,11 @@ namespace Xceed.Wpf.DataGrid throw new InvalidOperationException( "An attempt was made to change the FieldName of a cell already associated with a column." ); m_fieldName = value; + this.OnPropertyChanged( Cell.FieldNamePropertyName ); } } - internal void SetFieldName( string fieldName ) + private void SetFieldName( string fieldName ) { m_fieldName = fieldName; } @@ -1121,6 +1065,14 @@ namespace Xceed.Wpf.DataGrid this.SetValue( Cell.CoercedContentTemplatePropertyKey, newContentTemplate ); } + private void UpdateCoercedContentTemplate( bool force ) + { + if( force || this.IsContainerPrepared ) + { + this.SetCoercedContentTemplate( this.GetCoercedCellContentTemplate(), null ); + } + } + #endregion #region ContentTemplateInternal Property (private) @@ -1251,7 +1203,11 @@ namespace Xceed.Wpf.DataGrid var self = ( Cell )sender; Debug.Assert( self != null ); - var manager = TableflowView.GetColumnReorderingDragSourceManager( self.ParentColumn ); + var parentColumn = self.ParentColumn; + if( parentColumn == null ) + return newValue; + + var manager = TableflowView.GetColumnReorderingDragSourceManager( parentColumn ); if( manager == null ) return newValue; @@ -1308,8 +1264,8 @@ namespace Xceed.Wpf.DataGrid #region SelectionBackground Property - public static readonly DependencyProperty SelectionBackgroundProperty = - DependencyProperty.Register( "SelectionBackground", + public static readonly DependencyProperty SelectionBackgroundProperty = DependencyProperty.Register( + "SelectionBackground", typeof( Brush ), typeof( Cell ), new FrameworkPropertyMetadata( null ) ); @@ -1330,8 +1286,8 @@ namespace Xceed.Wpf.DataGrid #region SelectionForeground Property - public static readonly DependencyProperty SelectionForegroundProperty = - DependencyProperty.Register( "SelectionForeground", + public static readonly DependencyProperty SelectionForegroundProperty = DependencyProperty.Register( + "SelectionForeground", typeof( Brush ), typeof( Cell ), new FrameworkPropertyMetadata( null ) ); @@ -1352,8 +1308,8 @@ namespace Xceed.Wpf.DataGrid #region InactiveSelectionBackground Property - public static readonly DependencyProperty InactiveSelectionBackgroundProperty = - DependencyProperty.Register( "InactiveSelectionBackground", + public static readonly DependencyProperty InactiveSelectionBackgroundProperty = DependencyProperty.Register( + "InactiveSelectionBackground", typeof( Brush ), typeof( Cell ), new FrameworkPropertyMetadata( null ) ); @@ -1374,8 +1330,8 @@ namespace Xceed.Wpf.DataGrid #region InactiveSelectionForeground Property - public static readonly DependencyProperty InactiveSelectionForegroundProperty = - DependencyProperty.Register( "InactiveSelectionForeground", + public static readonly DependencyProperty InactiveSelectionForegroundProperty = DependencyProperty.Register( + "InactiveSelectionForeground", typeof( Brush ), typeof( Cell ), new FrameworkPropertyMetadata( null ) ); @@ -1503,15 +1459,28 @@ namespace Xceed.Wpf.DataGrid #endregion + #region IsContainerPartiallyCleared Property + + internal bool IsContainerPartiallyCleared + { + get + { + return m_flags[ ( int )CellFlags.IsContainerPartiallyCleared ]; + } + private set + { + m_flags[ ( int )CellFlags.IsContainerPartiallyCleared ] = value; + } + } + + #endregion + #region CanBeRecycled Property protected internal virtual bool CanBeRecycled { get { - if( this.IsDirty || this.HasValidationError || this.HasCellEditorError ) - return false; - if( !this.IsErrorStyleApplied ) { // We should not recycle the cell if the user has set a style or template explicitly. @@ -1531,6 +1500,25 @@ namespace Xceed.Wpf.DataGrid #endregion + #region CanBeCollapsed Property + + internal virtual bool CanBeCollapsed + { + get + { + if( this.IsCurrent || this.IsDirty || this.HasValidationError || this.IsBeingEdited || this.IsKeyboardFocused || this.IsKeyboardFocusWithin ) + return false; + + var parentColumn = this.ParentColumn; + if( parentColumn == null ) + return true; + + return !TableflowView.GetIsBeingDraggedAnimated( parentColumn ); + } + } + + #endregion + #region FocusEditor Property private bool FocusEditor @@ -1781,18 +1769,6 @@ namespace Xceed.Wpf.DataGrid #endregion - #region UpdateContentBindingTargetOnPrepareContainer Property - - protected virtual bool UpdateContentBindingTargetOnPrepareContainer - { - get - { - return true; - } - } - - #endregion - public static Cell FindFromChild( DependencyObject child ) { return Cell.FindFromChild( ( DataGridContext )null, child ); @@ -1892,18 +1868,18 @@ namespace Xceed.Wpf.DataGrid [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate" )] public double GetFittedWidth() { - if( ( this.IsContainerPrepared ) && ( !this.IsContainerVirtualized ) && ( this.VisualChildrenCount > 0 ) ) - { - UIElement element = this.GetVisualChild( 0 ) as UIElement; + if( !this.IsContainerPrepared || this.IsContainerVirtualized ) + return -1d; - if( element != null ) - { - element.Measure( new Size( double.PositiveInfinity, this.ActualHeight ) ); - return element.DesiredSize.Width; - } - } + this.ApplyTemplate(); + + var child = ( this.VisualChildrenCount > 0 ) ? this.GetVisualChild( 0 ) as UIElement : null; + if( child == null ) + return -1d; - return -1; + child.Measure( new Size( double.PositiveInfinity, this.ActualHeight ) ); + + return child.DesiredSize.Width; } protected override void OnMouseLeftButtonDown( MouseButtonEventArgs e ) @@ -1989,14 +1965,12 @@ namespace Xceed.Wpf.DataGrid if( e.Handled ) return; - Row parentRow = this.ParentRow; - + var parentRow = this.ParentRow; if( parentRow == null ) return; //Do not try to process the Activation Gesture if the Cell is readonly! - bool readOnly = this.GetInheritedReadOnly(); - + var readOnly = this.GetInheritedReadOnly(); if( readOnly ) return; @@ -2004,7 +1978,7 @@ namespace Xceed.Wpf.DataGrid if( !( parentRow.IsEditTriggerSet( EditTriggers.ActivationGesture ) ) ) return; - CellEditor editor = this.GetCellEditor(); + var editor = this.GetCellEditor(); //This condition is more complex and is used to filter cases were a TextInput is done and there is no need to process for activation keys... //Condition is: Editor is not null, editor is not displaued and editor is not pending showing. @@ -2084,33 +2058,33 @@ namespace Xceed.Wpf.DataGrid { base.OnVisualParentChanged( oldParent ); + // Since the parent property isn't a DP, we must update the binding ourself. this.UpdateParentForeground(); } - protected override AutomationPeer OnCreateAutomationPeer() + + protected override void OnPropertyChanged( DependencyPropertyChangedEventArgs e ) { - return new CellAutomationPeer( this ); + base.OnPropertyChanged( e ); + this.OnPropertyChanged( e.Property.Name ); } protected virtual void InitializeCore( DataGridContext dataGridContext, Row parentRow, ColumnBase parentColumn ) { - //Initialize the Cell's Properties. - this.SetParentRow( parentRow ); - this.SetParentColumn( parentColumn ); + this.ParentRow = parentRow; + this.ParentColumn = parentColumn; + + this.UpdateAnimatedColumnReorderingBindings( dataGridContext, Row.GetIsTemplateCell( this ) ); if( !this.IsInternalyInitialized ) { Binding rowMatchingConditionsBinding = new Binding(); - rowMatchingConditionsBinding.Path = new PropertyPath( "(0).(1)", - Cell.ParentRowProperty, - Row.RowDisplayEditorMatchingConditionsProperty ); + rowMatchingConditionsBinding.Path = new PropertyPath( "(0).(1)", Cell.ParentRowProperty, Row.RowDisplayEditorMatchingConditionsProperty ); rowMatchingConditionsBinding.Source = this; rowMatchingConditionsBinding.Mode = BindingMode.OneWay; //Initialize the RowDisplayEditorMatchingConditions binding to the ParentRow - BindingOperations.SetBinding( - this, Cell.RowDisplayEditorMatchingConditionsProperty, - rowMatchingConditionsBinding ); + BindingOperations.SetBinding( this, Cell.RowDisplayEditorMatchingConditionsProperty, rowMatchingConditionsBinding ); // Clear the FieldName since it will be taken from the column instead of directly from the Cell. this.SetFieldName( string.Empty ); @@ -2122,46 +2096,49 @@ namespace Xceed.Wpf.DataGrid if( !this.IsInternalyInitialized ) return null; - ColumnBase parentColumn = this.ParentColumn; + var parentColumnBase = this.ParentColumn; - if( parentColumn == null ) + if( parentColumnBase == null ) return null; - if( parentColumn.CellEditor != null ) - return parentColumn.CellEditor; + //Since the CellEditor property is set by default, first verify if the CelLEditorSelector property has been explicitly set. + if( parentColumnBase.CellEditorSelector != null ) + return parentColumnBase.CellEditorSelector.SelectCellEditor( parentColumnBase, this.DataContext ); + + if( parentColumnBase.CellEditor != null ) + return parentColumnBase.CellEditor; - Column column = parentColumn as Column; + var parentColumn = parentColumnBase as Column; - if( column != null ) + if( parentColumn != null ) { // Try to get a CellEditor from the ParentColumn.ForeignKeyConfiguration - ForeignKeyConfiguration configuration = column.ForeignKeyConfiguration; + var foreignKeyConfiguration = parentColumn.ForeignKeyConfiguration; - if( configuration != null ) + if( foreignKeyConfiguration != null ) { - return configuration.DefaultCellEditor; + return foreignKeyConfiguration.DefaultCellEditor; } } - object content = this.Content; + var content = this.Content; if( content == null ) return null; - Type contentType = content.GetType(); + var contentType = content.GetType(); - CellEditor cellEditor = DefaultCellEditorSelector.SelectCellEditor( contentType ); + var cellEditor = DefaultCellEditorSelector.SelectCellEditor( contentType ); if( cellEditor != null ) return cellEditor; - TypeConverter typeConverter = TypeDescriptor.GetConverter( contentType ); + var typeConverter = TypeDescriptor.GetConverter( contentType ); if( typeConverter == null ) return null; - if( typeConverter.CanConvertFrom( typeof( string ) ) - && ( typeConverter.CanConvertTo( typeof( string ) ) ) ) + if( typeConverter.CanConvertFrom( typeof( string ) ) && typeConverter.CanConvertTo( typeof( string ) ) ) { return DefaultCellEditorSelector.TextBoxEditor; } @@ -2225,51 +2202,47 @@ namespace Xceed.Wpf.DataGrid protected internal virtual void PrepareContainer( DataGridContext dataGridContext, object item ) { - object dataContext = this.DataContext; + this.IsContainerPartiallyCleared = false; // If the container is already prepared and not virtualized and the DataContext is the same, just ignore this call. // For example, a cell generated through the xaml parser can already be prepared (went through this method once) but // still have its DataContext set only after it has been prepared, thus the need to excute this method once more. - if( ( this.IsContainerPrepared ) && ( !this.IsContainerVirtualized ) && - ( ( dataContext == item ) || ( ( dataContext is UnboundDataItem ) && ( this.IsSameUnboundItem( dataContext, item ) ) ) ) ) + var dataContext = this.DataContext; + if( this.IsContainerPrepared && !this.IsContainerVirtualized && + ( ( dataContext == item ) || ( ( dataContext is UnboundDataItem ) && this.IsSameUnboundItem( dataContext, item ) ) ) ) return; //Make sure that the DataGridContext is set appropriatly on the cells that are already created. - //This is to ensure that teh value is appropriate when the container is recycled within another DataGridContext ( another detail on the same level ). + //This is to ensure that the value is appropriate when the container is recycled within another DataGridContext ( another detail on the same level ). DataGridControl.SetDataGridContext( this, dataGridContext ); - bool isNewDataContext; - ColumnBase parentColumn = this.ParentColumn; - - Cell.AssignDataContext( this, item, null, parentColumn, out isNewDataContext ); + var parentColumn = this.ParentColumn; + var isSameDataContext = Cell.AssignDataContext( this, item, null, parentColumn ); - if( !isNewDataContext && this.UpdateContentBindingTargetOnPrepareContainer ) + // In some scenarios, there may be validation errors on the content binding that is not reflected on the cell or the row, so make sure it is. + if( isSameDataContext && ( item is IDataErrorInfo ) && ( Validation.GetErrors( this ).Count > 0 ) && !this.HasValidationError + && !this.IsDirty) { - // The DataContext is already this item, update the cell's Content binding target in order for the validation to be once again evaluated. - this.UpdateContentBindingTarget(); + this.NotifyContentBindingValidationError(); } - Row parentRow = this.ParentRow; - ColumnBase currentColumn = dataGridContext.CurrentColumn; - // If there is a current column on the DataGridContext, try to restore the currency of the cell + var parentRow = this.ParentRow; + var currentColumn = dataGridContext.CurrentColumn; if( ( parentRow != null ) && ( parentRow.IsCurrent ) && ( currentColumn != null ) && ( currentColumn == parentColumn ) ) { this.SetIsCurrent( true ); } // This will force invalidation of the CoercedContentTemplate, only if the content is null after the prepare - // and if the content template is set to somethign else than default. However, when binded to an EmptyDataItem, - // our content will always be null but a CellContentTemplate will be applied. In this case, we do NOT want to - // reapplied the template every time. + // and if the content template is set to something else than default. However, when binded to an EmptyDataItem, + // our content will always be null but a CellContentTemplate will be applied. In this case, we do NOT want to reapplied the template every time. if( ( this.Content == null ) && ( !( this.GetRealDataContext() is EmptyDataItem ) ) ) { this.ClearValue( Cell.CoercedContentTemplatePropertyKey ); } - //Determine the default CellContentTemplate for the cell. - this.SetCoercedContentTemplate( this.GetCoercedCellContentTemplate(), null ); - + this.UpdateCoercedContentTemplate( true ); this.UpdateMatchingDisplayConditions(); // Ensure to reset both container recycling flags @@ -2287,47 +2260,70 @@ namespace Xceed.Wpf.DataGrid return; this.IsContainerPrepared = false; + this.IsContainerPartiallyCleared = false; + + this.AbortRefreshErrorStyle(); + this.AbortHideEditTemplate(); + + if( m_loadedRoutedEventHandler != null ) + { + this.Loaded -= m_loadedRoutedEventHandler; + m_loadedRoutedEventHandler = null; + } - // In DP's PropertyChanged Callbacks, for the sake of performance, you could - // return immediatly if the cell is in process of being cleared. + // In DP's PropertyChanged Callbacks, for the sake of performance, you could return immediatly if the cell is in process of being cleared. + this.ClearValue( Cell.StyleProperty ); this.ClearValue( Cell.IsCurrentPropertyKey ); + this.ClearValue( Cell.IsSelectedPropertyKey ); this.ClearValue( Cell.IsBeingEditedPropertyKey ); - this.SetIsSelected( false ); - this.SetIsCellEditorDisplayed( false ); + this.ClearValue( Cell.ValidationErrorPropertyKey ); + this.ClearValue( Cell.HasValidationErrorPropertyKey ); + this.ClearValue( Cell.IsValidationErrorRestrictivePropertyKey ); + + // We must not clear the IsDirty flag of the Cell here since its Content could have been edited and this flag is checked + // to determine if the new value is commited or not in the source + + // No need to clear the Cell.CellDisplayEditorMatchingConditionsProperty neither DataGridControl.CellEditorDisplayConditionsProperty since + // both will be updated when Cell.PrepareContainer is called again + + m_cellValidationRules = null; + m_styleBeforeError = DependencyProperty.UnsetValue; this.CurrentEditorPendingDisplayState = EditorDisplayState.None; this.IsContainerVirtualized = true; - // We must not clear the IsDirty flag of the Cell here since its - // Content could have been edited and this flag is checked - // to determine if the new value is commited or not in the source + this.SetIsCellEditorDisplayed( false ); - this.ClearValue( Cell.ValidationErrorPropertyKey ); + // This will reset every flags maintained in m_flags + this.ResetNonTransientFlags(); + } - // No need to clear the Cell.CellDisplayEditorMatchingConditionsProperty - // neither DataGridControl.CellEditorDisplayConditionsProperty since - // both will be updated when Cell.PrepareContainer is called again + protected internal virtual void PartialClearContainer() + { + // If the container is not prepared just ignore this call. + if( !this.IsContainerPrepared ) + return; + + this.IsContainerPartiallyCleared = true; this.AbortRefreshErrorStyle(); this.AbortHideEditTemplate(); - if( m_loadedRoutedEventHandler != null ) - { - this.Loaded -= m_loadedRoutedEventHandler; - m_loadedRoutedEventHandler = null; - } - + this.ClearValue( Cell.StyleProperty ); + this.ClearValue( Cell.IsCurrentPropertyKey ); + this.ClearValue( Cell.IsSelectedPropertyKey ); + this.ClearValue( Cell.IsBeingEditedPropertyKey ); + this.ClearValue( Cell.ValidationErrorPropertyKey ); this.ClearValue( Cell.HasValidationErrorPropertyKey ); this.ClearValue( Cell.IsValidationErrorRestrictivePropertyKey ); m_styleBeforeError = DependencyProperty.UnsetValue; - this.ClearValue( Cell.StyleProperty ); - this.ClearValue( Cell.IsSelectedPropertyKey ); + this.CurrentEditorPendingDisplayState = EditorDisplayState.None; + + this.SetIsCellEditorDisplayed( false ); // This will reset every flags maintained in m_flags this.ResetNonTransientFlags(); - - m_cellValidationRules = null; } protected internal virtual void PrepareDefaultStyleKey( Xceed.Wpf.DataGrid.Views.ViewBase view ) @@ -2347,6 +2343,21 @@ namespace Xceed.Wpf.DataGrid { } + protected internal virtual void CleanUpOnRemove() + { + this.AbortRefreshErrorStyle(); + this.AbortHideEditTemplate(); + + if( m_loadedRoutedEventHandler != null ) + { + this.Loaded -= m_loadedRoutedEventHandler; + m_loadedRoutedEventHandler = null; + } + + //This is done so the WeakEventListener on ParentColumn is removed. + this.ParentColumn = null; + } + internal static Cell FindFromChildOrSelf( DataGridControl dataGridControl, DependencyObject child ) { var cell = child as Cell; @@ -2472,24 +2483,16 @@ namespace Xceed.Wpf.DataGrid } } - internal static void AssignDataContext( Cell cell, object dataContext, UnboundDataItem unboundDataItemContext, ColumnBase parentColumn, out bool isNewDataContext ) + internal static bool AssignDataContext( Cell cell, object dataContext, UnboundDataItem unboundDataItemContext, ColumnBase parentColumn ) { - Column column = parentColumn as Column; - + var column = parentColumn as Column; if( ( column != null ) && ( column.IsBoundToDataGridUnboundItemProperty ) ) { - if( unboundDataItemContext == null ) - { - UnboundDataItem.GetUnboundDataItemNode( dataContext, out unboundDataItemContext ); - } - - dataContext = unboundDataItemContext; + dataContext = unboundDataItemContext ?? UnboundDataItem.GetUnboundDataItem( dataContext ); } - // Read the LocalValue of the DataContext to avoid - // getting the one inherited from the ParentRow. - // This prevent the DataContext to become null - // when the Cell is virtualized. + // Read the LocalValue of the DataContext to avoid getting the one inherited from the ParentRow. + // This prevent the DataContext to become null when the Cell is virtualized. object localDataContext = cell.ReadLocalValue( Cell.DataContextProperty ); if( localDataContext != dataContext ) @@ -2502,12 +2505,11 @@ namespace Xceed.Wpf.DataGrid cell.DataContext = null; } cell.DataContext = dataContext; - isNewDataContext = true; - } - else - { - isNewDataContext = false; + + return false; } + + return true; } //This ensures the CellEditorContext is set on the Cell to avoid problems with RelativeSource causing undesired behaviors when ComboBox is used as default CellEditor @@ -2515,27 +2517,26 @@ namespace Xceed.Wpf.DataGrid { ForeignKeyConfiguration configuration = null; - Column parentColumn = this.ParentColumn as Column; + var parentColumn = this.ParentColumn as Column; if( parentColumn != null ) { configuration = parentColumn.ForeignKeyConfiguration; - CellEditorContext context = new CellEditorContext( this.ParentColumn, configuration ); + CellEditorContext context = new CellEditorContext( parentColumn, configuration ); Cell.SetCellEditorContext( this, context ); } } internal void RefreshDisplayedTemplate() { - // Never refresh any templates when the Cell is not prepared - // or virtualized + // Never refresh any templates when the Cell is not prepared or virtualized if( !this.IsContainerPrepared || this.IsContainerVirtualized ) return; Row parentRow = this.ParentRow; // Never refresh template while clearing container - if( ( parentRow == null ) || ( parentRow.IsClearingContainer ) ) + if( ( parentRow == null ) || parentRow.IsClearingContainer ) return; if( this.ShouldDisplayEditor ) @@ -2590,16 +2591,14 @@ namespace Xceed.Wpf.DataGrid } this.SetIsDirty( false ); - this.SetIsDirtyFromInitializingInsertionRow( false ); } internal void UpdateContentBindingTarget() { - DataGridContext dataGridContext = DataGridControl.GetDataGridContext( this ); - // Never update the target of a binding to a an item if the Cell is dirty - if( ( !this.IsDirty ) && ( !this.IsDirtyFromInitializingInsertionRow ) ) + if( ( !this.IsDirty ) ) { + // We need to refresh the Cell.Content target binding in case the dataObject value was coerced to something else. BindingExpressionBase bindingExpression = this.GetContentBindingExpression(); if( bindingExpression != null ) @@ -2647,7 +2646,7 @@ namespace Xceed.Wpf.DataGrid } } - if( ( savedState.IsBeingEdited ) && ( this.ParentColumn == currentColumn ) ) + if( ( savedState.IsBeingEdited ) && ( parentColumn == currentColumn ) ) this.BeginEdit(); @@ -2656,20 +2655,19 @@ namespace Xceed.Wpf.DataGrid internal void OnIsTemplateCellChanged( bool newValue ) { - this.UpdateAnimatedColumnReorderingBindings( newValue ); + this.UpdateAnimatedColumnReorderingBindings( DataGridControl.GetDataGridContext( this ), newValue ); } internal ValidationResult UpdateContentBindingSource( out Exception exception, out CellValidationRule ruleInErrorWrapper ) { - Debug.Assert( ( ( this.IsDirty ) || ( this.IsDirtyFromInitializingInsertionRow ) || ( this.IsInCascadingValidation ) ), + Debug.Assert( ( ( this.IsDirty ) || ( this.IsInCascadingValidation ) ), "UpdateContentBindingSource should not be called when the cell isn't dirty beside when cascading validation. Call ValidateContentBindingRules instead." ); exception = null; ruleInErrorWrapper = null; - ValidationResult validationResult = ValidationResult.ValidResult; - - BindingExpressionBase contentBindingExpression = this.GetContentBindingExpression(); + var validationResult = ValidationResult.ValidResult; + var contentBindingExpression = this.GetContentBindingExpression(); if( contentBindingExpression != null ) { @@ -2693,13 +2691,9 @@ namespace Xceed.Wpf.DataGrid if( ( validationResult.IsValid ) || ( !( Cell.GetIsRuleInErrorRestrictive( ruleInErrorWrapper ) ) ) ) { this.ContentCommitted(); - - //Update StatsCells right away. - this.InvalidateStatsFunctions(); } - // The dirty flag will only be lowered when the row ends or cancels edition, or if the cell cancels edition and it wasn't dirty - // when begining edition. + // The dirty flag will only be lowered when the row ends or cancels edition, or if the cell cancels edition and it wasn't dirty when begining edition. return validationResult; } @@ -2758,51 +2752,21 @@ namespace Xceed.Wpf.DataGrid internal virtual bool GetCalculatedCanBeCurrent() { - if( this.GetInheritedReadOnly() ) - return ParentColumn.CanBeCurrentWhenReadOnly; - else + var column = this.ParentColumn; + if( ( column == null ) || ( this.ParentRow == null ) ) + return false; + + if( column.CanBeCurrentWhenReadOnly ) return true; - } - internal virtual void ContentCommitted() - { + return !this.GetInheritedReadOnly(); } - internal virtual void UpdateAnimatedColumnReorderingBindings( bool isTemplateCell ) + internal virtual void ContentCommitted() { - // Only set the Binding if the View is a TableflowView - DataGridContext dataGridContext = DataGridControl.GetDataGridContext( this ); - - if( dataGridContext != null ) - { - TableflowView tableflowView = dataGridContext.DataGridControl.GetView() as TableflowView; - - if( tableflowView == null ) - return; - } - - if( isTemplateCell ) - { - // No need to enable animated Column reordering when TemplateCell is used - BindingOperations.ClearBinding( this, Cell.RenderTransformProperty ); - BindingOperations.ClearBinding( this, Cell.ParentColumnIsBeingDraggedProperty ); - BindingOperations.ClearBinding( this, Cell.ParentColumnReorderingDragSourceManagerProperty ); - this.AnimatedColumnReorderingBindingApplied = false; - } - else - { - if( !this.AnimatedColumnReorderingBindingApplied ) - { - // To enable animated Column reordering - BindingOperations.SetBinding( this, Cell.RenderTransformProperty, Cell.ParentColumnTranslationBinding ); - BindingOperations.SetBinding( this, Cell.ParentColumnIsBeingDraggedProperty, Cell.ParentColumnIsBeingDraggedBinding ); - BindingOperations.SetBinding( this, Cell.ParentColumnReorderingDragSourceManagerProperty, Cell.ParentColumnReorderingDragSourceManagerBinding ); - this.AnimatedColumnReorderingBindingApplied = true; - } - } } - internal virtual void EnsureInVisualTree() + internal void EnsureInVisualTree() { DataGridContext dataGridContext = DataGridControl.GetDataGridContext( this ); if( dataGridContext == null ) @@ -2852,11 +2816,11 @@ namespace Xceed.Wpf.DataGrid private static object OnCoerceContent( DependencyObject sender, object value ) { - Cell cell = sender as Cell; + var cell = sender as Cell; // If we are updating the Content binding source and content is refreshed as a result, hold-on. // We will manually update Content from the source by calling UpdateTarget on the binding later. - if( cell.IsUpdatingContentBindingSource ) + if( ( cell != null ) && cell.IsUpdatingContentBindingSource ) return DependencyProperty.UnsetValue; return value; @@ -2864,23 +2828,25 @@ namespace Xceed.Wpf.DataGrid private static void OnContentChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - Cell cell = ( Cell )sender; - Row parentRow = cell.ParentRow; + var cell = sender as Cell; + if( cell == null ) + return; + var parentRow = cell.ParentRow; if( parentRow == null ) return; - bool doCellValidation = false; - ColumnBase parentColumn = cell.ParentColumn; + var doCellValidation = false; + var parentColumn = cell.ParentColumn; - bool changeDuringRowIsInEdit = ( cell.IsInternalyInitialized ) + var changeDuringRowIsInEdit = ( cell.IsInternalyInitialized ) && ( !cell.IsContainerRecycled ) && ( !parentRow.IsBeginningEdition ) && ( !cell.IsUpdatingContentBindingSource ) && ( !cell.IsRestoringEditionState ) && ( parentRow.IsBeingEdited ); - if( ( changeDuringRowIsInEdit ) || ( parentRow.IsInitializingInsertionRow ) ) + if( changeDuringRowIsInEdit ) { if( parentColumn != null ) { @@ -2896,19 +2862,7 @@ namespace Xceed.Wpf.DataGrid } } - if( parentRow.IsInitializingInsertionRow ) - { - Nullable dataGridUpdateSourceTrigger = cell.GetContentBindingUpdateSourceTrigger(); - - if( ( dataGridUpdateSourceTrigger == DataGridUpdateSourceTrigger.CellContentChanged ) - || ( dataGridUpdateSourceTrigger == DataGridUpdateSourceTrigger.CellEndingEdit ) ) - { - doCellValidation = true; - } - - cell.SetIsDirtyFromInitializingInsertionRow( true ); - } - else if( changeDuringRowIsInEdit ) + if( changeDuringRowIsInEdit ) { if( !object.Equals( e.OldValue, e.NewValue ) ) { @@ -2917,9 +2871,7 @@ namespace Xceed.Wpf.DataGrid if( !cell.PreventValidateAndSetAllErrors ) { - Nullable dataGridUpdateSourceTrigger = cell.GetContentBindingUpdateSourceTrigger(); - - if( dataGridUpdateSourceTrigger == DataGridUpdateSourceTrigger.CellContentChanged ) + if( cell.GetContentBindingUpdateSourceTrigger() == DataGridUpdateSourceTrigger.CellContentChanged ) { doCellValidation = true; } @@ -2933,31 +2885,35 @@ namespace Xceed.Wpf.DataGrid // We would be surprised of such a usage, but this fail-safe will take care of this possibility. if( !cell.GetIsSiblingUpdatingContentBindingSource() ) { + // The CellEditorRules must not be ckecked when UpdateSourceTrigger is set to CellContentChanged because the editor's HasValidationError property + // changes only AFTER the new cell value is commited. It would thus result in nothing being processed here if it were to be checked. + Exception exception; CellValidationRule ruleInError; - - - - ValidationResult validationResult = cell.ValidateCellRules( out exception, out ruleInError ); - + var validationResult = cell.ValidateCellRules( out exception, out ruleInError ); if( validationResult.IsValid ) + { cell.ValidateAndSetAllErrors( false, false, true, true, out exception, out ruleInError ); + } } } //When the content changes, check if the CellContentTemplateSelector needs to be updated. //This depdends on several factor, including if a Selector is present and if the editor is not displayed - if( cell.ShouldInvalidateCellContentTemplateSelector() ) + if( cell.ShouldInvalidateCellContentTemplateSelector( parentColumn ) ) { - cell.SetCoercedContentTemplate( cell.GetCoercedCellContentTemplate(), null ); + cell.UpdateCoercedContentTemplate( false ); } } private static void OnIsDirtyChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { + var cell = sender as Cell; + if( cell == null ) + return; + if( ( bool )e.NewValue ) { - Cell cell = ( Cell )sender; //Raise the RoutedEvent that notifies any Row that the cell is becoming dirty. RoutedEventArgs eventArgs = new RoutedEventArgs( Cell.IsDirtyEvent ); cell.RaiseEvent( eventArgs ); @@ -2966,22 +2922,27 @@ namespace Xceed.Wpf.DataGrid private static void OnMatchingDisplayEditorChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - Cell obj = ( Cell )sender; + var cell = sender as Cell; + if( cell == null ) + return; //performing this check because at the end of the Initializing function, I will call this explicitelly, to ensure //proper display of the Editor if the appropriate conditions are met. - if( obj.IsInternalyInitialized ) + if( cell.IsInternalyInitialized ) { - obj.RefreshDisplayedTemplate(); + cell.RefreshDisplayedTemplate(); } } private static void OnCellEditorDisplayConditionsChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - Cell cell = ( Cell )sender; + var cell = sender as Cell; + if( cell == null ) + return; // The cell.ParentRow can be null if this Cell is a TemplateCell - if( ( cell.ParentRow != null ) && cell.ParentRow.IsClearingContainer ) + var parentRow = cell.ParentRow; + if( ( parentRow != null ) && parentRow.IsClearingContainer ) return; cell.UpdateMatchingDisplayConditions(); @@ -2989,9 +2950,7 @@ namespace Xceed.Wpf.DataGrid private static void OnContentTemplateChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - Cell cell = sender as Cell; - Debug.Assert( cell != null ); - + var cell = sender as Cell; if( cell == null ) return; @@ -2999,15 +2958,13 @@ namespace Xceed.Wpf.DataGrid if( ( cell.CurrentEditorPendingDisplayState != EditorDisplayState.PendingShow ) && ( !cell.IsCellEditorDisplayed ) ) { - cell.SetCoercedContentTemplate( cell.GetCoercedCellContentTemplate(), null ); + cell.UpdateCoercedContentTemplate( false ); } } private static void OnContentTemplateSelectorChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - Cell cell = sender as Cell; - Debug.Assert( cell != null ); - + var cell = sender as Cell; if( cell == null ) return; @@ -3015,18 +2972,17 @@ namespace Xceed.Wpf.DataGrid if( ( cell.CurrentEditorPendingDisplayState != EditorDisplayState.PendingShow ) && ( !cell.IsCellEditorDisplayed ) ) { - cell.SetCoercedContentTemplate( cell.GetCoercedCellContentTemplate(), null ); + cell.UpdateCoercedContentTemplate( false ); } } private static void OnIsTemplateCellChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - Cell cell = sender as Cell; + var cell = sender as Cell; + if( cell == null ) + return; - if( cell != null ) - { - cell.OnIsTemplateCellChanged( ( bool )e.NewValue ); - } + cell.OnIsTemplateCellChanged( ( bool )e.NewValue ); } private bool GetInheritedReadOnly() @@ -3084,7 +3040,7 @@ namespace Xceed.Wpf.DataGrid isReadOnly = this.ReadOnly; } - if( ( bool )isReadOnly ) + if( isReadOnly ) return true; var contentBindingExpression = this.GetContentBindingExpression(); @@ -3104,48 +3060,36 @@ namespace Xceed.Wpf.DataGrid return ( contentBindingMode.HasValue ) && ( contentBindingMode.Value != BindingMode.TwoWay ); } - private bool ShouldInvalidateCellContentTemplateSelector() + private bool ShouldInvalidateCellContentTemplateSelector( ColumnBase parentColumn ) { - ColumnBase parentColumn = this.ParentColumn; - - bool onlyInternalContentTemplateSelectorAvailable = - ( ( this.ContentTemplateInternal == null ) && ( this.ContentTemplateSelectorInternal != null ) ); - - bool onlyColumnContentTemplateSelectorAvailable = - ( ( parentColumn.CellContentTemplate == null ) && ( parentColumn.CellContentTemplateSelector != null ) ); - - bool onlyTemplateSelectorAvailable = onlyColumnContentTemplateSelectorAvailable - || onlyInternalContentTemplateSelectorAvailable; + if( parentColumn == null ) + return false; - bool editorHiddenAndNotPendingShow = !this.IsCellEditorDisplayed - && ( this.CurrentEditorPendingDisplayState != EditorDisplayState.PendingShow ); + var onlyInternalContentTemplateSelectorAvailable = ( ( this.ContentTemplateInternal == null ) && ( this.ContentTemplateSelectorInternal != null ) ); + var onlyColumnContentTemplateSelectorAvailable = ( ( parentColumn.CellContentTemplate == null ) && ( parentColumn.CellContentTemplateSelector != null ) ); + var onlyTemplateSelectorAvailable = onlyColumnContentTemplateSelectorAvailable || onlyInternalContentTemplateSelectorAvailable; + var editorHiddenAndNotPendingShow = !this.IsCellEditorDisplayed && ( this.CurrentEditorPendingDisplayState != EditorDisplayState.PendingShow ); - // Only TemplateSelectors are avaiable and editor is not hidden and pending showing + // Only TemplateSelectors are available and editor is not hidden and pending showing return ( onlyTemplateSelectorAvailable && editorHiddenAndNotPendingShow ); } private bool GetIsContentBindingSupportingSourceUpdate() { - BindingExpressionBase binding = this.GetContentBindingExpression(); - + var binding = this.GetContentBindingExpression(); if( binding == null ) return false; BindingMode mode; - Binding singleBinding = binding.ParentBindingBase as Binding; + var singleBinding = binding.ParentBindingBase as Binding; if( singleBinding == null ) { - MultiBinding multiBinding = binding.ParentBindingBase as MultiBinding; - + var multiBinding = binding.ParentBindingBase as MultiBinding; if( multiBinding == null ) - { return false; - } - else - { - mode = multiBinding.Mode; - } + + mode = multiBinding.Mode; } else { @@ -3160,8 +3104,7 @@ namespace Xceed.Wpf.DataGrid // This method is called to make sure we are not calling ValidateAndSetAllErrors at all nor triggering a cascade validation // as a side-effect of updating a cell's content binding source while another cell is bound to the very same source. // We would be surprised of such a usage, but this fail-safe will take care of this possibility. - Row parentRow = this.ParentRow; - + var parentRow = this.ParentRow; if( parentRow != null ) { foreach( Cell siblingCell in parentRow.CreatedCells ) @@ -3200,7 +3143,7 @@ namespace Xceed.Wpf.DataGrid var parentColumn = this.ParentColumn; //If there was no ContentTemplateSelector on Cell or if the output of the selector was Null. - if( ( !this.OverrideColumnCellContentTemplate ) && ( contentTemplate == null ) ) + if( ( !this.OverrideColumnCellContentTemplate ) && ( contentTemplate == null ) && ( parentColumn != null ) ) { contentTemplate = this.GetForeignKeyDataTemplate(); if( contentTemplate != null ) @@ -3230,15 +3173,12 @@ namespace Xceed.Wpf.DataGrid contentTemplate = GenericContentTemplateSelector.Instance.SelectTemplate( content, this ); } - if( contentTemplate != null ) + if( ( contentTemplate != null ) && ( parentColumn != null ) && !string.IsNullOrEmpty( parentColumn.CellContentStringFormat ) ) { - if( ( parentColumn != null ) && !string.IsNullOrEmpty( parentColumn.CellContentStringFormat ) ) + var newContentTemplate = this.GetCellStringFormatDataTemplate( contentTemplate ); + if( newContentTemplate != null ) { - var newContentTemplate = this.GetCellStringFormatDataTemplate( contentTemplate ); - if( newContentTemplate != null ) - { - contentTemplate = newContentTemplate; - } + contentTemplate = newContentTemplate; } } @@ -3302,6 +3242,32 @@ namespace Xceed.Wpf.DataGrid return unboundDataItem.DataItem == item; } + private void UpdateAnimatedColumnReorderingBindings( DataGridContext dataGridContext, bool isTemplateCell ) + { + // Only set the Binding if the view is a TableflowView. + var setBindings = ( !isTemplateCell ) + && ( dataGridContext != null ) + && ( dataGridContext.DataGridControl.GetView() is TableflowView ); + + if( setBindings == this.AnimatedColumnReorderingBindingApplied ) + return; + + if( setBindings ) + { + BindingOperations.SetBinding( this, Cell.RenderTransformProperty, Cell.ParentColumnTranslationBinding ); + BindingOperations.SetBinding( this, Cell.ParentColumnIsBeingDraggedProperty, Cell.ParentColumnIsBeingDraggedBinding ); + BindingOperations.SetBinding( this, Cell.ParentColumnReorderingDragSourceManagerProperty, Cell.ParentColumnReorderingDragSourceManagerBinding ); + } + else + { + BindingOperations.ClearBinding( this, Cell.RenderTransformProperty ); + BindingOperations.ClearBinding( this, Cell.ParentColumnIsBeingDraggedProperty ); + BindingOperations.ClearBinding( this, Cell.ParentColumnReorderingDragSourceManagerProperty ); + } + + this.AnimatedColumnReorderingBindingApplied = setBindings; + } + private void ShowEditTemplate() { this.AbortHideEditTemplate(); @@ -3310,11 +3276,9 @@ namespace Xceed.Wpf.DataGrid if( this.CurrentEditorPendingDisplayState != EditorDisplayState.PendingShow ) { // If it is not displayed or pending hiding - if( !this.IsCellEditorDisplayed - || ( this.CurrentEditorPendingDisplayState == EditorDisplayState.PendingHide ) ) + if( !this.IsCellEditorDisplayed || ( this.CurrentEditorPendingDisplayState == EditorDisplayState.PendingHide ) || m_forceEditorRefresh ) { - CellEditor cellEditor = this.GetCellEditor(); - + var cellEditor = this.GetCellEditor(); if( cellEditor != null ) { this.SetCoercedContentTemplate( this.GetCoercedCellContentTemplate(), cellEditor.EditTemplate ); @@ -3340,8 +3304,7 @@ namespace Xceed.Wpf.DataGrid if( ( !this.IsCellEditorDisplayed ) && ( this.CurrentEditorPendingDisplayState != EditorDisplayState.PendingShow ) ) return; - m_delayedHideEditTemplateDispatcherOperation = this.Dispatcher.BeginInvoke( - new Action( this.HideEditTemplate ), DispatcherPriority.DataBind ); + m_delayedHideEditTemplateDispatcherOperation = this.Dispatcher.BeginInvoke( new Action( this.HideEditTemplate ), DispatcherPriority.DataBind ); } private void AbortHideEditTemplate() @@ -3364,8 +3327,7 @@ namespace Xceed.Wpf.DataGrid if( !this.IsContainerPrepared || this.IsContainerVirtualized ) return; - if( ( !this.IsCellEditorDisplayed ) - && ( this.CurrentEditorPendingDisplayState != EditorDisplayState.PendingShow ) ) + if( !this.IsCellEditorDisplayed && ( this.CurrentEditorPendingDisplayState != EditorDisplayState.PendingShow ) ) return; this.SetCoercedContentTemplate( this.GetCoercedCellContentTemplate(), null ); @@ -3427,32 +3389,51 @@ namespace Xceed.Wpf.DataGrid this.SetValue( Cell.CellDisplayEditorMatchingConditionsProperty, newEffectiveValue ); } - private void InvalidateStatsFunctions() + private void UpdateFocusable() { - //Make sure to update StatFunctions as soon as cell content changes (this part of the code is executed only if UpdateSourceTrigger is set to CellContentChanged). - DataGridContext dataGridContext = DataGridControl.GetDataGridContext( this ); - DataGridControl dataGridControl = dataGridContext.DataGridControl; + var isFocusable = false; + var dataGridContext = DataGridControl.GetDataGridContext( this ); - if( dataGridControl != null ) + if( dataGridContext != null ) { - DataGridCollectionView dataGridCollectionView = dataGridControl.ItemsSource as DataGridCollectionView; + var column = this.ParentColumn; + var dataGridControl = dataGridContext.DataGridControl; - if( ( dataGridCollectionView != null ) && ( dataGridCollectionView.StatFunctions.Count > 0 ) ) - { - int currentIndex; + Debug.Assert( dataGridControl != null ); - //If -1 is returned, it means the corresponding data item is not yet in the source (e.g insertion cell), so no stats to update at this point. - if( ( currentIndex = dataGridCollectionView.IndexOf( this.ParentRow.DataContext ) ) == -1 ) - return; - - RawItem item = dataGridCollectionView.GetRawItemAt( currentIndex ); + if( ( !this.GetCalculatedCanBeCurrent() ) && ( column != null ) && ( column == dataGridContext.CurrentColumn ) ) + { + try + { + dataGridContext.SetCurrentColumnCore( null, false, dataGridControl.SynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.CurrentColumnChanged ); + } + catch( DataGridException ) + { + // We swallow the exception if it occurs because of a validation error or Cell was read-only or + // any other GridException. + } + } - DataGridCollectionViewGroup parentGroup = item.ParentGroup; + isFocusable = true; - if( parentGroup != null ) - dataGridCollectionView.DeferredOperationManager.InvalidateGroupStats( parentGroup ); + if( !this.IsBeingEdited ) + { + var row = this.ParentRow; + if( row != null ) + { + switch( row.NavigationBehavior ) + { + case NavigationBehavior.None: + case NavigationBehavior.RowOnly: + isFocusable = false; + break; + } + } } } + + //force an update of the NavigationBehavior characteristics + this.Focusable = isFocusable && this.GetCalculatedCanBeCurrent(); } private void OnBeginEditExecuted( object sender, ExecutedRoutedEventArgs e ) @@ -3482,8 +3463,9 @@ namespace Xceed.Wpf.DataGrid } else { - e.CanExecute = ( !this.IsBeingEdited ) && ( !this.GetInheritedReadOnly() ) - && ( this.ParentRow.IsEditTriggerSet( EditTriggers.BeginEditCommand ) ); + e.CanExecute = ( !this.IsBeingEdited ) + && ( !this.GetInheritedReadOnly() ) + && ( this.ParentRow.IsEditTriggerSet( EditTriggers.BeginEditCommand ) ); } } } @@ -3519,13 +3501,7 @@ namespace Xceed.Wpf.DataGrid //If the Cell is marked to be pending the display of the editor, then //this LayoutUpdated means that Editor has been effectively displayed - // Notify the UIAutomation if any children have changed. - AutomationPeer automationPeer = UIElementAutomationPeer.FromElement( this ); - if( automationPeer != null ) - { - automationPeer.ResetChildrenCache(); - } //Change the IsCellEditorDisplayed flag accordingly this.SetIsCellEditorDisplayed( true ); @@ -3535,13 +3511,7 @@ namespace Xceed.Wpf.DataGrid //If the Cell is marked to be pending the Display of the viewer, then //this LayoutUpdated means that Editor has been effectively hidden - // Notify the UIAutomation if any children have changed. - AutomationPeer automationPeer = UIElementAutomationPeer.FromElement( this ); - if( automationPeer != null ) - { - automationPeer.ResetChildrenCache(); - } //Change the IsCellEditorDisplayed flag accordingly this.SetIsCellEditorDisplayed( false ); @@ -3732,19 +3702,16 @@ namespace Xceed.Wpf.DataGrid if( this.IsBeingEdited ) return; - bool readOnly = this.GetInheritedReadOnly(); - + var readOnly = this.GetInheritedReadOnly(); if( readOnly ) throw new DataGridException( "An attempt was made to edit a read-only cell or the cell content is not bound using two way binding." ); // If there is no dataItem mapped to this container, we don't want to // enter in edition var dataGridContext = DataGridControl.GetDataGridContext( this ); - if( dataGridContext != null ) { - object dataItem = dataGridContext.GetItemFromContainer( this ); - + var dataItem = dataGridContext.GetItemFromContainer( this ); if( dataItem == null ) return; } @@ -3823,7 +3790,9 @@ namespace Xceed.Wpf.DataGrid if( !this.IsBeingEdited ) return; - bool updateContentBindingSource = this.GetContentBindingUpdateSourceTrigger() == DataGridUpdateSourceTrigger.CellEndingEdit; + var dataGridUpdateSourceTrigger = this.GetContentBindingUpdateSourceTrigger(); + var updateContentBindingSource = ( dataGridUpdateSourceTrigger == DataGridUpdateSourceTrigger.CellEndingEdit ) + || ( dataGridUpdateSourceTrigger == DataGridUpdateSourceTrigger.CellContentChanged ); this.EndEdit( true, true, updateContentBindingSource ); } @@ -3873,11 +3842,9 @@ namespace Xceed.Wpf.DataGrid this.PreventValidateAndSetAllErrors = false; } - Nullable dataGridUpdateSourceTrigger = this.GetContentBindingUpdateSourceTrigger(); - - bool updateContentBindingSource = - ( dataGridUpdateSourceTrigger == DataGridUpdateSourceTrigger.CellEndingEdit ) || - ( dataGridUpdateSourceTrigger == DataGridUpdateSourceTrigger.CellContentChanged ); + var dataGridUpdateSourceTrigger = this.GetContentBindingUpdateSourceTrigger(); + var updateContentBindingSource = ( dataGridUpdateSourceTrigger == DataGridUpdateSourceTrigger.CellEndingEdit ) + || ( dataGridUpdateSourceTrigger == DataGridUpdateSourceTrigger.CellContentChanged ); Exception exception; CellValidationRule ruleInError; @@ -3893,7 +3860,6 @@ namespace Xceed.Wpf.DataGrid } } - this.SetIsDirtyFromInitializingInsertionRow( false ); this.SetIsBeingEdited( false ); this.OnEditCanceled(); } @@ -3937,10 +3903,10 @@ namespace Xceed.Wpf.DataGrid if( !this.IsBeingEdited ) return; - CancelRoutedEventArgs e = new CancelRoutedEventArgs( Cell.EditEndingEvent, this ); - try { + var e = new CancelRoutedEventArgs( Cell.EditEndingEvent, this ); + this.OnEditEnding( e ); // Throwing a DataGridValidationException will be caught by the grid and will make the cell stay in edition. @@ -3951,15 +3917,14 @@ namespace Xceed.Wpf.DataGrid //This has been identified, and only the places where it caused problems were fixed... This comment is only here to remind developpers of the flaw if( ( !this.IsKeyboardFocused ) && ( this.IsKeyboardFocusWithin ) ) { - DataGridContext dataGridContext = DataGridControl.GetDataGridContext( this ); + var dataGridContext = DataGridControl.GetDataGridContext( this ); if( ( dataGridContext != null ) && ( !dataGridContext.DataGridControl.IsSetFocusInhibited ) ) { // Prevent the focus to make a RequestBringIntoView using( this.InhibitMakeVisible() ) { - // We want to try to focus the Cell before we continue the EndEdit to ensure - // any validation or process in the lost focus is done + // We want to try to focus the Cell before we continue the EndEdit to ensure any validation or process in the lost focus is done if( !dataGridContext.DataGridControl.SetFocusHelper( this.ParentRow, this.ParentColumn, false, false ) ) throw new DataGridFocusException( "Unable to set focus on the Cell." ); } @@ -3969,7 +3934,9 @@ namespace Xceed.Wpf.DataGrid catch( Exception exception ) { if( exception is TargetInvocationException ) + { exception = exception.InnerException; + } // In the case it's the focus that failed, we don't want to make that a ValidationError since it // must be retained by the editor itself with his own error mechanic. @@ -3980,11 +3947,7 @@ namespace Xceed.Wpf.DataGrid if( exception is DataGridFocusException ) throw; - this.SetValidationError( new CellValidationError( - Cell.CustomCellValidationExceptionValidationRule, - this, - exception.Message, - exception ) ); + this.SetValidationError( new CellValidationError( Cell.CustomCellValidationExceptionValidationRule, this, exception.Message, exception ) ); // Throwing a DataGridValidationException will be caught by the grid and will make the cell stay in edition. throw new DataGridValidationException( "An error occurred while attempting to end the edit process.", exception ); @@ -3992,17 +3955,15 @@ namespace Xceed.Wpf.DataGrid Exception notUsed; CellValidationRule ruleInError; + var result = this.ValidateAndSetAllErrors( validateCellEditorRules, validateUIRules, updateContentBindingSource, true, out notUsed, out ruleInError ); - ValidationResult result = - this.ValidateAndSetAllErrors( validateCellEditorRules, validateUIRules, updateContentBindingSource, true, out notUsed, out ruleInError ); - - - CellState cellState = this.GetEditCachedState(); - + var cellState = this.GetEditCachedState(); if( cellState != null ) { if( result.IsValid ) + { cellState.SetContentBeforeCellEdition( DependencyProperty.UnsetValue ); + } cellState.SetIsDirtyBeforeEdition( null ); } @@ -4077,7 +4038,7 @@ namespace Xceed.Wpf.DataGrid DataGridControl.GetDataGridContext( this ).DataGridControl ); } - ValidationResult result = ValidationResult.ValidResult; + var result = ValidationResult.ValidResult; exception = null; ruleInError = null; @@ -4104,16 +4065,14 @@ namespace Xceed.Wpf.DataGrid { // Only need to update the Content binding source if the cell is dirty or if we are cascading the validation. if( ( updateContentBindingSource ) - && ( ( this.IsDirty ) || ( this.IsDirtyFromInitializingInsertionRow ) || ( this.IsInCascadingValidation ) ) ) + && ( ( this.IsDirty ) || ( this.IsInCascadingValidation ) ) ) { // Update the Content binding's source and check for errors. result = this.UpdateContentBindingSource( out exception, out ruleInError ); } else { - // Just check for errors. - // We must validate even if the cell isn't dirty since its value might have been in error even before - // entering edit on the row. + // Just check for errors. We must validate even if the cell isn't dirty since its value might have been in error even before entering edit on the row. // ie: DataErrorInfo or any other non-restrictive validation error. result = this.ValidateContentBindingRules( out exception, out ruleInError ); } @@ -4126,7 +4085,9 @@ namespace Xceed.Wpf.DataGrid this.SetAllError( result, exception, ruleInError ); if( cascadeValidate ) + { this.CascadeValidation(); + } } return result; @@ -4159,50 +4120,50 @@ namespace Xceed.Wpf.DataGrid this.SetAllError( ValidationResult.ValidResult, null, null ); } - private static void ContentBinding_ValidationError( object sender, ValidationErrorEventArgs e ) + private static void OnContentBindingNotifyValidationError( object sender, ValidationErrorEventArgs e ) { Cell cell = ( Cell )sender; - if( cell.PreventValidateAndSetAllErrors ) + cell.NotifyContentBindingValidationError(); + } + + internal void NotifyContentBindingValidationError() + { + if( this.PreventValidateAndSetAllErrors ) return; // Proceed only if the isn't any UI ValidationRules error flagged since last UI validation pass. - if( cell.HasUIValidationError ) + if( this.HasUIValidationError ) return; - ValidationError cellContentBindingValidationError = cell.GetContentBindingValidationError(); + var validationError = this.GetContentBindingValidationError(); - // In order to minimize switching of styles when we need to update the Content Binding's source, - // the SetAllError method will not do anything while it is being prevented. - // - // ie: When we need to update the ContentBinding's source manually through EndEdit. - if( cellContentBindingValidationError != null ) + // In order to minimize switching of styles when we need to update the Content Binding's source, the SetAllError method will not do anything while it is being prevented. + // e.g. : When we need to update the ContentBinding's source manually through EndEdit. + if( validationError != null ) { - cell.SetAllError( - new ValidationResult( false, cellContentBindingValidationError.ErrorContent ), - cellContentBindingValidationError.Exception, - new CellContentBindingValidationRule( cellContentBindingValidationError.RuleInError ) ); + this.SetAllError( new ValidationResult( false, validationError.ErrorContent ), validationError.Exception, + new CellContentBindingValidationRule( validationError.RuleInError ) ); } else { - cell.SetAllError( ValidationResult.ValidResult, null, null ); + this.SetAllError( ValidationResult.ValidResult, null, null ); } } - private void ContentBinding_TargetUpdated( object sender, DataTransferEventArgs e ) + private void OnContentBindingTargetUpdated( object sender, DataTransferEventArgs e ) { if( e.Property != Cell.ContentProperty ) return; - Cell cell = e.TargetObject as Cell; + var cell = e.TargetObject as Cell; - // Under certain circumstances which have not yet been clearly identified, the TargetObject - // is the ContentPresenter of the ScrollTip. This would raise a NullReferenceException when - // trying to access cell's members, as the previous cast would return null. + // Under certain circumstances which have not yet been clearly identified, the TargetObject is the ContentPresenter of the ScrollTip. + // This would raise a NullReferenceException when trying to access cell's members, as the previous cast would return null. if( cell == null ) return; - Row parentRow = cell.ParentRow; + var parentRow = cell.ParentRow; if( ( cell.IsUpdatingContentBindingSource ) || ( cell.PreventValidateAndSetAllErrors ) || ( parentRow == null ) || ( !parentRow.IsBeingEdited ) || ( !parentRow.IsDirty ) ) @@ -4218,24 +4179,23 @@ namespace Xceed.Wpf.DataGrid Exception exception; CellValidationRule ruleInError; - cell.ValidateAndSetAllErrors( false, true, false, true, out exception, out ruleInError ); } private void CascadeValidation() { - Row parentRow = this.ParentRow; + var parentRow = this.ParentRow; if( parentRow == null ) return; - bool updateContentBindingSource = ( parentRow.IsEndingEdition || parentRow.IsCancelingEdition ) - || ( this.GetContentBindingUpdateSourceTrigger() == DataGridUpdateSourceTrigger.CellEndingEdit ) - || ( this.GetContentBindingUpdateSourceTrigger() == DataGridUpdateSourceTrigger.CellContentChanged ); + var dataGridUpdateSourceTrigger = this.GetContentBindingUpdateSourceTrigger(); + var updateContentBindingSource = ( parentRow.IsEndingEdition || parentRow.IsCancelingEdition ) + || ( dataGridUpdateSourceTrigger == DataGridUpdateSourceTrigger.CellEndingEdit ) + || ( dataGridUpdateSourceTrigger == DataGridUpdateSourceTrigger.CellContentChanged ); - // Create a clone of the list to avoid concurrent access when iterating - // and a Cell is added to CreatedCells because of ColumnVirtualization - List createdCells = new List( parentRow.CreatedCells ); + // Create a clone of the list to avoid concurrent access when iterating and a Cell is added to CreatedCells because of ColumnVirtualization + var createdCells = new List( parentRow.CreatedCells ); foreach( Cell siblingCell in createdCells ) { @@ -4252,7 +4212,6 @@ namespace Xceed.Wpf.DataGrid { Exception exception; CellValidationRule ruleInError; - siblingCell.ValidateAndSetAllErrors( false, true, updateContentBindingSource, false, out exception, out ruleInError ); } finally @@ -4268,8 +4227,7 @@ namespace Xceed.Wpf.DataGrid if( invalid ) { - CellValidationError validationError = - new CellValidationError( ruleInError, this, result.ErrorContent, validationException ); + CellValidationError validationError = new CellValidationError( ruleInError, this, result.ErrorContent, validationException ); this.SetValidationError( validationError ); } @@ -4285,8 +4243,7 @@ namespace Xceed.Wpf.DataGrid ruleInError = null; validationException = null; - CellValidationContext cellValidationContext = - new CellValidationContext( this.GetRealDataContext(), this ); + CellValidationContext cellValidationContext = new CellValidationContext( this.GetRealDataContext(), this ); CultureInfo culture = this.Language.GetSpecificCulture(); @@ -4382,142 +4339,82 @@ namespace Xceed.Wpf.DataGrid bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) { - return this.OnReceivedWeakEvent( managerType, sender, e ); + return this.OnReceiveWeakEvent( managerType, sender, e ); } - protected internal virtual bool OnReceivedWeakEvent( Type managerType, object sender, EventArgs e ) + protected virtual bool OnReceiveWeakEvent( Type managerType, object sender, EventArgs e ) { - bool retval = false; - - if( managerType == typeof( CanBeCurrentWhenReadOnlyChangedEventManager ) ) - { - ColumnBase column = sender as ColumnBase; - - if( this.ProcessEvent( column, out retval ) ) - { - this.OnParentColumnCanBeCurrentWhenReadOnlyChanged( column ); - } - } - else if( managerType == typeof( CellEditorDisplayConditionsChangedEventManager ) ) + if( managerType == typeof( PropertyChangedEventManager ) ) { - ColumnBase column = sender as ColumnBase; - - if( this.ProcessEvent( column, out retval ) ) - { - this.OnParentColumnCellEditorDisplayConditionsChanged(); - } - } - else if( managerType == typeof( CellContentTemplateChangedEventManager ) ) - { - ColumnBase column = sender as ColumnBase; - - if( this.ProcessEvent( column, out retval ) ) + var column = sender as ColumnBase; + if( ( column != null ) && ( column == this.ParentColumn ) ) { - this.OnParentColumnCellContentTemplateChanged( false ); + this.OnParentColumnPropertyChanged( ( PropertyChangedEventArgs )e ); } } - else if( managerType == typeof( CellContentStringFormatChangedEventManager ) ) - { - ColumnBase column = sender as ColumnBase; - - if( this.ProcessEvent( column, out retval ) ) - { - this.OnParentColumnCellContentTemplateChanged( true ); - } - } - else if( managerType == typeof( ForeignKeyConfigurationChangedEventManager ) ) + else { - Column column = sender as Column; - - if( this.ProcessEvent( column, out retval ) ) - { - this.OnParentColumnForeignKeyConfigurationChanged(); - } + return false; } - return retval; + return true; } - private bool ProcessEvent( ColumnBase column, out bool handled ) + internal virtual void OnParentColumnPropertyChanged( PropertyChangedEventArgs e ) { - handled = ( column != null ) && ( column.DataGridControl != null ); - - return ( handled ) && ( this.IsContainerPrepared ) && ( !this.IsContainerVirtualized ); - } + if( !this.IsContainerPrepared || this.IsContainerVirtualized ) + return; - private void OnParentColumnCanBeCurrentWhenReadOnlyChanged( ColumnBase column ) - { - DataGridControl dataGridControl = column.DataGridControl; - DataGridContext dataGridContext = dataGridControl.DataGridContext; + var propertyName = e.PropertyName; - if( ( !this.GetCalculatedCanBeCurrent() ) && ( column == dataGridContext.CurrentColumn ) ) + if( string.IsNullOrEmpty( propertyName ) ) { - try + if( !this.IsCellEditorDisplayed && ( this.CurrentEditorPendingDisplayState != EditorDisplayState.PendingShow ) ) { - dataGridContext.SetCurrentColumnCore( null, false, dataGridControl.SynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.CurrentColumnChanged ); - } - catch( DataGridException ) - { - // We swallow the exception if it occurs because of a validation error or Cell was read-only or - // any other GridException. + this.UpdateCoercedContentTemplate( false ); } - } - bool cellFocusable = true; - - if( !this.IsBeingEdited ) + this.UpdateFocusable(); + this.UpdateMatchingDisplayConditions(); + } + else if( propertyName == ColumnBase.CanBeCurrentWhenReadOnlyProperty.Name ) + { + this.UpdateFocusable(); + } + else if( propertyName == ColumnBase.CellEditorDisplayConditionsProperty.Name ) { - switch( this.ParentRow.NavigationBehavior ) + this.UpdateMatchingDisplayConditions(); + } + else if( ( propertyName == ColumnBase.CellContentTemplateProperty.Name ) + || ( propertyName == ColumnBase.CellContentTemplateSelectorProperty.Name ) ) + { + if( !this.IsCellEditorDisplayed && ( this.CurrentEditorPendingDisplayState != EditorDisplayState.PendingShow ) ) { - case NavigationBehavior.None: - cellFocusable = false; - break; - case NavigationBehavior.RowOnly: - cellFocusable = false; - break; - case NavigationBehavior.RowOrCell: - cellFocusable = true; - break; - case NavigationBehavior.CellOnly: - cellFocusable = true; - break; + if( ( this.ContentTemplateInternal == null ) && ( this.ContentTemplateSelectorInternal == null ) ) + { + this.UpdateCoercedContentTemplate( false ); + } } } - - //force an update of the NavigationBehavior characteristics - this.Focusable = ( cellFocusable && this.GetCalculatedCanBeCurrent() ); - } - - private void OnParentColumnCellEditorDisplayConditionsChanged() - { - this.UpdateMatchingDisplayConditions(); - } - - private void OnParentColumnCellContentTemplateChanged( bool ignoreTemplateConditions ) - { - //If the editor is displayed, I want to take no actions for this event. - if( ( this.CurrentEditorPendingDisplayState == EditorDisplayState.PendingShow ) || ( this.IsCellEditorDisplayed ) ) - return; - - //If there is no local value for the ContentTemplate and ContentTemplateSelector properties, then it is possible that - //the template to use changed. - if( ignoreTemplateConditions - || ( ( this.ContentTemplateInternal == null ) && ( this.ContentTemplateSelectorInternal == null ) ) ) + else if( ( propertyName == ColumnBase.CellContentStringFormatProperty.Name ) + || ( propertyName == ColumnBase.DefaultCultureProperty.Name ) + || ( propertyName == Column.ForeignKeyConfigurationProperty.Name ) ) { - //force a re-evaluation of the CellContentTemplate. - this.SetCoercedContentTemplate( this.GetCoercedCellContentTemplate(), null ); + if( !this.IsCellEditorDisplayed && ( this.CurrentEditorPendingDisplayState != EditorDisplayState.PendingShow ) ) + { + this.UpdateCoercedContentTemplate( false ); + } } - } - - private void OnParentColumnForeignKeyConfigurationChanged() - { - if( ( this.CurrentEditorPendingDisplayState != EditorDisplayState.PendingShow ) && ( !this.IsCellEditorDisplayed ) ) + else if( propertyName == ColumnBase.CellEditorSelectorProperty.Name ) { - this.SetCoercedContentTemplate( this.GetCoercedCellContentTemplate(), null ); + //Make sure the editor is refreshed even if it is currently displayed. + m_forceEditorRefresh = true; + this.RefreshDisplayedTemplate(); + m_forceEditorRefresh = false; } } - #endregion IWeakEventListener Members + #endregion private KeyActivationGesture m_keyGesture; // = null private TextCompositionEventArgs m_textInputArgs; // = null @@ -4529,6 +4426,7 @@ namespace Xceed.Wpf.DataGrid private DispatcherOperation m_delayedHideEditTemplateDispatcherOperation; private BitVector32 m_flags = new BitVector32(); + private bool m_forceEditorRefresh; // Binding used by the animated Column reordering feature private static Binding ParentColumnTranslationBinding; @@ -4564,7 +4462,8 @@ namespace Xceed.Wpf.DataGrid IsContainerVirtualized = 32768, AnimatedColumnReorderingBindingApplied = 65536, PreventMakeVisible = 131072, - IsContainerRecycled = 262144 + IsContainerRecycled = 262144, + IsContainerPartiallyCleared = 524288 } #endregion diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellContentPresenter.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellContentPresenter.cs index 2a2cbae8..e0bd4aff 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellContentPresenter.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellContentPresenter.cs @@ -14,15 +14,10 @@ ***********************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Windows; using System.Windows.Controls; -using System.Diagnostics; -using System.Windows.Threading; using System.Windows.Data; +using System.Windows.Documents; namespace Xceed.Wpf.DataGrid { @@ -30,6 +25,13 @@ namespace Xceed.Wpf.DataGrid { static CellContentPresenter() { + CellContentPresenter.MinHeightProperty.OverrideMetadata( typeof( CellContentPresenter ), new FrameworkPropertyMetadata( null, new CoerceValueCallback( CellContentPresenter.CoerceMinHeight ) ) ); + TextElement.FontFamilyProperty.OverrideMetadata( typeof( CellContentPresenter ), new FrameworkPropertyMetadata( new PropertyChangedCallback( CellContentPresenter.InvalidateMinHeight ) ) ); + TextElement.FontSizeProperty.OverrideMetadata( typeof( CellContentPresenter ), new FrameworkPropertyMetadata( new PropertyChangedCallback( CellContentPresenter.InvalidateMinHeight ) ) ); + TextElement.FontStretchProperty.OverrideMetadata( typeof( CellContentPresenter ), new FrameworkPropertyMetadata( new PropertyChangedCallback( CellContentPresenter.InvalidateMinHeight ) ) ); + TextElement.FontStyleProperty.OverrideMetadata( typeof( CellContentPresenter ), new FrameworkPropertyMetadata( new PropertyChangedCallback( CellContentPresenter.InvalidateMinHeight ) ) ); + TextElement.FontWeightProperty.OverrideMetadata( typeof( CellContentPresenter ), new FrameworkPropertyMetadata( new PropertyChangedCallback( CellContentPresenter.InvalidateMinHeight ) ) ); + m_sContentBinding = new Binding(); m_sContentBinding.RelativeSource = RelativeSource.TemplatedParent; m_sContentBinding.Mode = BindingMode.OneWay; @@ -59,12 +61,15 @@ namespace Xceed.Wpf.DataGrid m_sTextBlockStyle = new Style( typeof( TextBlock ) ); m_sTextBlockStyle.Setters.Add( new Setter( TextBlock.TextTrimmingProperty, trimmingBinding ) ); m_sTextBlockStyle.Setters.Add( new Setter( TextBlock.TextWrappingProperty, wrappingBinding ) ); + m_sTextBlockStyle.Seal(); } public CellContentPresenter() { this.Resources.Add( typeof( TextBlock ), m_sTextBlockStyle ); this.DataContext = null; + + this.SetCurrentValue( CellContentPresenter.MinHeightProperty, 0d ); } public override void EndInit() @@ -75,11 +80,26 @@ namespace Xceed.Wpf.DataGrid BindingOperations.SetBinding( this, CellContentPresenter.ContentTemplateProperty, m_sContentTemplateBinding ); } + private static object CoerceMinHeight( DependencyObject sender, object value ) + { + var self = sender as CellContentPresenter; + if( self == null ) + return value; + + return self.CoerceMinHeight( new Thickness(), value ); + } + + private static void InvalidateMinHeight( DependencyObject sender, DependencyPropertyChangedEventArgs e ) + { + var self = sender as CellContentPresenter; + if( self == null ) + return; + + self.CoerceValue( CellContentPresenter.MinHeightProperty ); + } + private static Binding m_sContentTemplateBinding; private static Binding m_sContentBinding; - private static Style m_sTextBlockStyle; } - - } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellContentStringFormatChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellContentStringFormatChangedEventManager.cs deleted file mode 100644 index c3414964..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellContentStringFormatChangedEventManager.cs +++ /dev/null @@ -1,74 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class CellContentStringFormatChangedEventManager : WeakEventManager - { - private CellContentStringFormatChangedEventManager() - { - } - - public static void AddListener( ColumnBase source, IWeakEventListener listener ) - { - CellContentStringFormatChangedEventManager.CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( ColumnBase source, IWeakEventListener listener ) - { - CellContentStringFormatChangedEventManager.CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - var column = ( ColumnBase )source; - - column.CellContentStringFormatChanged += new EventHandler( this.OnCellContentStringFormatChanged ); - } - - protected override void StopListening( object source ) - { - var column = ( ColumnBase )source; - - column.CellContentStringFormatChanged -= new EventHandler( this.OnCellContentStringFormatChanged ); - } - - private static CellContentStringFormatChangedEventManager CurrentManager - { - get - { - var managerType = typeof( CellContentStringFormatChangedEventManager ); - var currentManager = ( CellContentStringFormatChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new CellContentStringFormatChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnCellContentStringFormatChanged( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellContentTemplateChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellContentTemplateChangedEventManager.cs deleted file mode 100644 index f2d46f09..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellContentTemplateChangedEventManager.cs +++ /dev/null @@ -1,72 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class CellContentTemplateChangedEventManager : WeakEventManager - { - private CellContentTemplateChangedEventManager() - { - } - - public static void AddListener( ColumnBase source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( ColumnBase source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - ColumnBase column = ( ColumnBase )source; - column.CellContentTemplateChanged += new EventHandler( this.OnCellContentTemplateChanged ); - } - - protected override void StopListening( object source ) - { - ColumnBase column = ( ColumnBase )source; - column.CellContentTemplateChanged -= new EventHandler( this.OnCellContentTemplateChanged ); - } - - private static CellContentTemplateChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( CellContentTemplateChangedEventManager ); - CellContentTemplateChangedEventManager currentManager = ( CellContentTemplateChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new CellContentTemplateChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnCellContentTemplateChanged( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellEditorDisplayConditionsChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellEditorDisplayConditionsChangedEventManager.cs deleted file mode 100644 index 91a1c3aa..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellEditorDisplayConditionsChangedEventManager.cs +++ /dev/null @@ -1,72 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class CellEditorDisplayConditionsChangedEventManager : WeakEventManager - { - private CellEditorDisplayConditionsChangedEventManager() - { - } - - public static void AddListener( ColumnBase source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - public static void RemoveListener( ColumnBase source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - ColumnBase column = ( ColumnBase )source; - column.CellEditorDisplayConditionsChanged += new EventHandler( this.OnCellEditorDisplayConditionsChanged ); - } - - protected override void StopListening( object source ) - { - ColumnBase column = ( ColumnBase )source; - column.CellEditorDisplayConditionsChanged -= new EventHandler( this.OnCellEditorDisplayConditionsChanged ); - } - - private static CellEditorDisplayConditionsChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( CellEditorDisplayConditionsChangedEventManager ); - CellEditorDisplayConditionsChangedEventManager currentManager = ( CellEditorDisplayConditionsChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new CellEditorDisplayConditionsChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnCellEditorDisplayConditionsChanged( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Stats/StatResult.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellEditorSelector.cs similarity index 68% rename from ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Stats/StatResult.cs rename to ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellEditorSelector.cs index 39ba63ba..39d6984a 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Stats/StatResult.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CellEditorSelector.cs @@ -1,38 +1,26 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; - -namespace Xceed.Wpf.DataGrid.Stats -{ - internal class StatResult - { - public StatResult( object value ) - { - m_value = value; - } - - private object m_value; - - public object Value - { - get - { - return m_value; - } - } - } -} +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +namespace Xceed.Wpf.DataGrid +{ + public abstract class CellEditorSelector + { + public virtual CellEditor SelectCellEditor( ColumnBase column, object item ) + { + return null; + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ChildColumnVisibilityChangedEventManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ChildColumnVisibilityChangedEventManager.cs deleted file mode 100644 index cbec599a..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ChildColumnVisibilityChangedEventManager.cs +++ /dev/null @@ -1,75 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal class ChildColumnVisibilityChangedEventManager : WeakEventManager - { - private ChildColumnVisibilityChangedEventManager() - { - } - - internal static void AddListener( ObservableColumnCollection source, IWeakEventListener listener ) - { - CurrentManager.ProtectedAddListener( source, listener ); - } - - internal static void RemoveListener( ObservableColumnCollection source, IWeakEventListener listener ) - { - CurrentManager.ProtectedRemoveListener( source, listener ); - } - - protected override void StartListening( object source ) - { - var columnCollection = ( ObservableColumnCollection )source; - columnCollection.ColumnVisibilityChanged += new EventHandler( this.OnColumnVisibilityChanged ); - } - - protected override void StopListening( object source ) - { - var columnCollection = ( ObservableColumnCollection )source; - columnCollection.ColumnVisibilityChanged -= new EventHandler( this.OnColumnVisibilityChanged ); - } - - private static ChildColumnVisibilityChangedEventManager CurrentManager - { - get - { - Type managerType = typeof( ChildColumnVisibilityChangedEventManager ); - ChildColumnVisibilityChangedEventManager currentManager = ( ChildColumnVisibilityChangedEventManager )WeakEventManager.GetCurrentManager( managerType ); - - if( currentManager == null ) - { - currentManager = new ChildColumnVisibilityChangedEventManager(); - WeakEventManager.SetCurrentManager( managerType, currentManager ); - } - - return currentManager; - } - } - - private void OnColumnVisibilityChanged( object sender, EventArgs args ) - { - this.DeliverEvent( sender, args ); - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Column.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Column.cs index d6574901..48b7010d 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Column.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Column.cs @@ -20,12 +20,24 @@ using System.ComponentModel; using System.Diagnostics; using System.Windows; using System.Windows.Data; +using Xceed.Wpf.DataGrid.Utils; namespace Xceed.Wpf.DataGrid { [DebuggerDisplay( "FieldName = {FieldName}" )] public class Column : ColumnBase { + #region Static Fields + + internal static readonly string AllowSortPropertyName = PropertyHelper.GetPropertyName( ( Column c ) => c.AllowSort ); + internal static readonly string AllowGroupPropertyName = PropertyHelper.GetPropertyName( ( Column c ) => c.AllowGroup ); +#pragma warning disable 618 + internal static readonly string DisplayMemberBindingPropertyName = PropertyHelper.GetPropertyName( ( Column c ) => c.DisplayMemberBinding ); +#pragma warning restore 618 + internal static readonly string DisplayMemberBindingInfoPropertyName = PropertyHelper.GetPropertyName( ( Column c ) => c.DisplayMemberBindingInfo ); + + #endregion + public Column() { } @@ -68,7 +80,7 @@ namespace Xceed.Wpf.DataGrid m_displayMemberBinding = value; - this.OnPropertyChanged( new PropertyChangedEventArgs( "DisplayMemberBinding" ) ); + this.OnPropertyChanged( new PropertyChangedEventArgs( Column.DisplayMemberBindingPropertyName ) ); } } @@ -110,7 +122,7 @@ namespace Xceed.Wpf.DataGrid m_displayMemberBindingInfo = value; m_displayMemberBinding = m_displayMemberBindingInfo.GetBinding(); - this.OnPropertyChanged( new PropertyChangedEventArgs( "DisplayMemberBindingInfo" ) ); + this.OnPropertyChanged( new PropertyChangedEventArgs( Column.DisplayMemberBindingInfoPropertyName ) ); } } } @@ -131,7 +143,7 @@ namespace Xceed.Wpf.DataGrid return; m_allowSort = value; - this.OnPropertyChanged( new PropertyChangedEventArgs( "AllowSort" ) ); + this.OnPropertyChanged( new PropertyChangedEventArgs( Column.AllowSortPropertyName ) ); } } @@ -153,7 +165,7 @@ namespace Xceed.Wpf.DataGrid return; m_allowGroup = value; - this.OnPropertyChanged( new PropertyChangedEventArgs( "AllowGroup" ) ); + this.OnPropertyChanged( new PropertyChangedEventArgs( Column.AllowGroupPropertyName ) ); } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnBase.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnBase.cs index b230fc38..a9968741 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnBase.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnBase.cs @@ -16,6 +16,7 @@ using System; using System.Collections; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; @@ -24,7 +25,7 @@ using System.Globalization; using System.Windows; using System.Windows.Controls; using System.Windows.Data; -using Xceed.Utils.Collections; +using Xceed.Wpf.DataGrid.Utils; using Xceed.Wpf.DataGrid.ValidationRules; using Xceed.Wpf.DataGrid.Views; @@ -52,15 +53,35 @@ namespace Xceed.Wpf.DataGrid this.Title = title; } - #region CellContentTemplate Property + #region Description Property + + public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register( + "Description", + typeof( string ), + typeof( ColumnBase ), + new UIPropertyMetadata( null ) ); + + public string Description + { + get + { + return ( string )this.GetValue( ColumnBase.DescriptionProperty ); + } + set + { + this.SetValue( ColumnBase.DescriptionProperty, value ); + } + } - internal event EventHandler CellContentTemplateChanged; + #endregion - public static readonly DependencyProperty CellContentTemplateProperty = - DependencyProperty.Register( "CellContentTemplate", - typeof( DataTemplate ), - typeof( ColumnBase ), - new FrameworkPropertyMetadata( null, new PropertyChangedCallback( ColumnBase.OnCellContentTemplateChanged ) ) ); + #region CellContentTemplate Property + + public static readonly DependencyProperty CellContentTemplateProperty = DependencyProperty.Register( + "CellContentTemplate", + typeof( DataTemplate ), + typeof( ColumnBase ), + new FrameworkPropertyMetadata( null, new PropertyChangedCallback( ColumnBase.OnCellContentTemplateChanged ) ) ); public DataTemplate CellContentTemplate { @@ -74,18 +95,26 @@ namespace Xceed.Wpf.DataGrid } } - #endregion CellContentTemplate Property + private static void OnCellContentTemplateChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) + { + var self = sender as ColumnBase; + if( self == null ) + return; + + //Make sure cells pertaining to this group are assigned to the correct recycle bin. + //The recycle bin based on the previous key value will be clean up later by the FixedCellPanel, if no other column uses it. + self.ResetDefaultCellRecyclingGroup(); + } + + #endregion #region CellContentTemplateSelector Property - public static readonly DependencyProperty CellContentTemplateSelectorProperty = - DependencyProperty.Register( - "CellContentTemplateSelector", - typeof( DataTemplateSelector ), - typeof( ColumnBase ), - new FrameworkPropertyMetadata( - GenericContentTemplateSelector.Instance, - new PropertyChangedCallback( ColumnBase.OnCellContentTemplateSelectorChanged ) ) ); + public static readonly DependencyProperty CellContentTemplateSelectorProperty = DependencyProperty.Register( + "CellContentTemplateSelector", + typeof( DataTemplateSelector ), + typeof( ColumnBase ), + new FrameworkPropertyMetadata( GenericContentTemplateSelector.Instance, new PropertyChangedCallback( ColumnBase.OnCellContentTemplateSelectorChanged ) ) ); public DataTemplateSelector CellContentTemplateSelector { @@ -99,15 +128,26 @@ namespace Xceed.Wpf.DataGrid } } - #endregion CellContentTemplateSelector Property + private static void OnCellContentTemplateSelectorChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) + { + var self = sender as ColumnBase; + if( self == null ) + return; + + //Make sure cells pertaining to this group are assigned to the correct recycle bin. + //The recycle bin based on the previous key value will be clean up later by the FixedCellPanel, if no other column uses it. + self.ResetDefaultCellRecyclingGroup(); + } + + #endregion #region CellHorizontalContentAlignment Property - public static readonly DependencyProperty CellHorizontalContentAlignmentProperty = - DependencyProperty.Register( "CellHorizontalContentAlignment", - typeof( HorizontalAlignment ), - typeof( ColumnBase ), - new FrameworkPropertyMetadata( HorizontalAlignment.Stretch ) ); + public static readonly DependencyProperty CellHorizontalContentAlignmentProperty = DependencyProperty.Register( + "CellHorizontalContentAlignment", + typeof( HorizontalAlignment ), + typeof( ColumnBase ), + new FrameworkPropertyMetadata( HorizontalAlignment.Stretch ) ); public HorizontalAlignment CellHorizontalContentAlignment { @@ -121,15 +161,15 @@ namespace Xceed.Wpf.DataGrid } } - #endregion CellHorizontalContentAlignment + #endregion #region CellVerticalContentAlignment Property - public static readonly DependencyProperty CellVerticalContentAlignmentProperty = - DependencyProperty.Register( "CellVerticalContentAlignment", - typeof( VerticalAlignment ), - typeof( ColumnBase ), - new FrameworkPropertyMetadata( VerticalAlignment.Stretch ) ); + public static readonly DependencyProperty CellVerticalContentAlignmentProperty = DependencyProperty.Register( + "CellVerticalContentAlignment", + typeof( VerticalAlignment ), + typeof( ColumnBase ), + new FrameworkPropertyMetadata( VerticalAlignment.Stretch ) ); public VerticalAlignment CellVerticalContentAlignment { @@ -143,16 +183,15 @@ namespace Xceed.Wpf.DataGrid } } - #endregion CellVerticalContentAlignment + #endregion #region CellContentStringFormat Property - //StringFormat to use when in ViewMode (not editing) - public static readonly DependencyProperty CellContentStringFormatProperty = - DependencyProperty.Register( "CellContentStringFormat", - typeof( string ), - typeof( ColumnBase ), - new FrameworkPropertyMetadata( null, new PropertyChangedCallback( ColumnBase.OnCellContentStringFormatChanged ) ) ); + public static readonly DependencyProperty CellContentStringFormatProperty = DependencyProperty.Register( + "CellContentStringFormat", + typeof( string ), + typeof( ColumnBase ), + new FrameworkPropertyMetadata( null ) ); public string CellContentStringFormat { @@ -166,9 +205,7 @@ namespace Xceed.Wpf.DataGrid } } - internal event EventHandler CellContentStringFormatChanged; - - #endregion CellContentStringFormat Property + #endregion #region Title Property @@ -176,9 +213,7 @@ namespace Xceed.Wpf.DataGrid "Title", typeof( object ), typeof( ColumnBase ), - new UIPropertyMetadata( - null, - new PropertyChangedCallback( ColumnBase.OnTitleChanged ) ) ); + new UIPropertyMetadata( null ) ); public object Title { @@ -192,20 +227,7 @@ namespace Xceed.Wpf.DataGrid } } - private static void OnTitleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) - { - var column = ( ColumnBase )sender; - var handler = column.TitleChanged; - - if( handler != null ) - { - handler.Invoke( column, EventArgs.Empty ); - } - } - - internal event EventHandler TitleChanged; - - #endregion Title Property + #endregion #region TitleTemplate Property @@ -227,7 +249,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion TitleTemplate Property + #endregion #region TitleTemplateSelector Property @@ -249,7 +271,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion TitleTemplateSelector Property + #endregion #region ActualWidth Property @@ -320,7 +342,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion ActualWidth Property + #endregion #region Width Property @@ -380,12 +402,11 @@ namespace Xceed.Wpf.DataGrid column.UpdateActualWidth(); } - #endregion Width Property + #endregion #region MinWidth Property - public static readonly DependencyProperty MinWidthProperty = - FrameworkElement.MinWidthProperty.AddOwner( typeof( ColumnBase ), new PropertyMetadata( new PropertyChangedCallback( ColumnBase.WidthChanged ) ) ); + public static readonly DependencyProperty MinWidthProperty = FrameworkElement.MinWidthProperty.AddOwner( typeof( ColumnBase ), new PropertyMetadata( new PropertyChangedCallback( ColumnBase.WidthChanged ) ) ); public double MinWidth { @@ -399,12 +420,11 @@ namespace Xceed.Wpf.DataGrid } } - #endregion MinWidth Property + #endregion #region MaxWidth Property - public static readonly DependencyProperty MaxWidthProperty = - FrameworkElement.MaxWidthProperty.AddOwner( typeof( ColumnBase ), new PropertyMetadata( new PropertyChangedCallback( ColumnBase.WidthChanged ) ) ); + public static readonly DependencyProperty MaxWidthProperty = FrameworkElement.MaxWidthProperty.AddOwner( typeof( ColumnBase ), new PropertyMetadata( new PropertyChangedCallback( ColumnBase.WidthChanged ) ) ); public double MaxWidth { @@ -418,12 +438,11 @@ namespace Xceed.Wpf.DataGrid } } - #endregion MaxWidth Property + #endregion #region DesiredWidth Property - internal static readonly DependencyProperty DesiredWidthProperty = - DependencyProperty.Register( "DesiredWidth", typeof( double ), typeof( ColumnBase ), new PropertyMetadata( -1d, new PropertyChangedCallback( ColumnBase.WidthChanged ) ) ); + internal static readonly DependencyProperty DesiredWidthProperty = DependencyProperty.Register( "DesiredWidth", typeof( double ), typeof( ColumnBase ), new PropertyMetadata( -1d, new PropertyChangedCallback( ColumnBase.WidthChanged ) ) ); internal double DesiredWidth { @@ -437,7 +456,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion DesiredWidth Property + #endregion #region TextTrimming Property @@ -459,7 +478,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion TextTrimming Property + #endregion #region TextWrapping Property @@ -481,7 +500,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion TextWrapping Property + #endregion #region HasFixedWidth Read-Only Property @@ -505,12 +524,11 @@ namespace Xceed.Wpf.DataGrid } } - #endregion HasFixedWidth Read-Only Property + #endregion #region VisiblePosition Property - public static readonly DependencyProperty VisiblePositionProperty = - DependencyProperty.Register( + public static readonly DependencyProperty VisiblePositionProperty = DependencyProperty.Register( "VisiblePosition", typeof( int ), typeof( ColumnBase ), @@ -556,10 +574,9 @@ namespace Xceed.Wpf.DataGrid private static void OnVisiblePositionChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - ColumnBase column = ( ColumnBase )sender; - - int oldValue = ( int )e.OldValue; - int newValue = ( int )e.NewValue; + var column = ( ColumnBase )sender; + var oldValue = ( int )e.OldValue; + var newValue = ( int )e.NewValue; var handler = column.VisiblePositionChanged; if( handler != null ) @@ -589,7 +606,7 @@ namespace Xceed.Wpf.DataGrid private readonly AutoResetFlag m_inhibitVisiblePositionChanging = AutoResetFlagFactory.Create( false ); - #endregion VisiblePosition Property + #endregion #region IsFirstVisible Read-Only Property @@ -619,7 +636,7 @@ namespace Xceed.Wpf.DataGrid this.ClearValue( ColumnBase.IsFirstVisiblePropertyKey ); } - #endregion IsFirstVisible Read-Only Property + #endregion #region IsLastVisible Read-Only Property @@ -649,7 +666,7 @@ namespace Xceed.Wpf.DataGrid this.ClearValue( ColumnBase.IsLastVisiblePropertyKey ); } - #endregion IsLastVisible Read-Only Property + #endregion #region FieldName Property @@ -683,7 +700,7 @@ namespace Xceed.Wpf.DataGrid return requestedValue; } - #endregion FieldName Property + #endregion #region Visible Property @@ -691,7 +708,7 @@ namespace Xceed.Wpf.DataGrid "Visible", typeof( bool ), typeof( ColumnBase ), - new UIPropertyMetadata( true, new PropertyChangedCallback( ColumnBase.OnVisibilityChanged ) ) ); + new UIPropertyMetadata( true ) ); public bool Visible { @@ -705,20 +722,7 @@ namespace Xceed.Wpf.DataGrid } } - private static void OnVisibilityChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) - { - var column = ( ColumnBase )sender; - - var handler = column.VisibleChanged; - if( handler != null ) - { - handler.Invoke( column, EventArgs.Empty ); - } - } - - internal event EventHandler VisibleChanged; - - #endregion Visible Property + #endregion #region Index Property @@ -733,7 +737,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion Index Property + #endregion #region DataGridControl Property @@ -750,10 +754,12 @@ namespace Xceed.Wpf.DataGrid internal void NotifyDataGridControlChanged() { - this.OnPropertyChanged( new PropertyChangedEventArgs( "DataGridControl" ) ); + this.OnPropertyChanged( new PropertyChangedEventArgs( ColumnBase.DataGridControlPropertyName ) ); } - #endregion DataGridControl Property + internal static readonly string DataGridControlPropertyName = PropertyHelper.GetPropertyName( ( ColumnBase c ) => c.DataGridControl ); + + #endregion #region ParentDetailConfiguration Property @@ -768,7 +774,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion ParentDetailConfiguration Property + #endregion #region ContainingCollection Property @@ -780,7 +786,9 @@ namespace Xceed.Wpf.DataGrid } } - #endregion ContainingCollection Property + private ColumnCollection m_containingCollection; //null + + #endregion #region AllowSort Property @@ -796,7 +804,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion AllowSort Property + #endregion #region AllowGroup Property @@ -812,7 +820,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion AllowGroup Property + #endregion #region GroupValueTemplate Property @@ -834,7 +842,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion GroupValueTemplate Property + #endregion #region GroupValueTemplateSelector Property @@ -856,7 +864,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion GroupValueTemplateSelector Property + #endregion #region GroupValueStringFormat Property @@ -878,7 +886,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion GroupValueStringFormat Property + #endregion #region CellEditor Property @@ -900,46 +908,47 @@ namespace Xceed.Wpf.DataGrid } } - #endregion CellEditor Property - - #region CellEditorDisplayConditions Property + #endregion - public static readonly DependencyProperty CellEditorDisplayConditionsProperty = - DataGridControl.CellEditorDisplayConditionsProperty.AddOwner( typeof( ColumnBase ), new FrameworkPropertyMetadata( new PropertyChangedCallback( ColumnBase.OnCellEditorDisplayConditionsChanged ) ) ); + #region CellEditorSelector Property - private CellEditorDisplayConditions m_cellEditorDisplayConditions; + public static readonly DependencyProperty CellEditorSelectorProperty = DependencyProperty.Register( + "CellEditorSelector", + typeof( CellEditorSelector ), + typeof( ColumnBase ), + new FrameworkPropertyMetadata( null ) ); - public CellEditorDisplayConditions CellEditorDisplayConditions + public CellEditorSelector CellEditorSelector { get { - return m_cellEditorDisplayConditions; + return ( CellEditorSelector )this.GetValue( ColumnBase.CellEditorSelectorProperty ); } set { - this.SetValue( ColumnBase.CellEditorDisplayConditionsProperty, value ); + this.SetValue( ColumnBase.CellEditorSelectorProperty, value ); } } - internal event EventHandler CellEditorDisplayConditionsChanged; - - private static void OnCellEditorDisplayConditionsChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) - { - ColumnBase column = ( ColumnBase )sender; + #endregion - if( column == null ) - return; + #region CellEditorDisplayConditions Property - if( e.NewValue != null ) - column.m_cellEditorDisplayConditions = ( CellEditorDisplayConditions )e.NewValue; + public static readonly DependencyProperty CellEditorDisplayConditionsProperty = DataGridControl.CellEditorDisplayConditionsProperty.AddOwner( typeof( ColumnBase ) ); - if( column.CellEditorDisplayConditionsChanged != null ) + public CellEditorDisplayConditions CellEditorDisplayConditions + { + get { - column.CellEditorDisplayConditionsChanged( column, EventArgs.Empty ); + return ( CellEditorDisplayConditions )this.GetValue( ColumnBase.CellEditorDisplayConditionsProperty ); + } + set + { + this.SetValue( ColumnBase.CellEditorDisplayConditionsProperty, value ); } } - #endregion CellEditorDisplayConditions Property + #endregion #region CellValidationRules Property @@ -948,7 +957,9 @@ namespace Xceed.Wpf.DataGrid get { if( m_cellValidationRules == null ) + { m_cellValidationRules = new Collection(); + } return m_cellValidationRules; } @@ -956,12 +967,11 @@ namespace Xceed.Wpf.DataGrid private Collection m_cellValidationRules; // = null - #endregion CellValidationRules Property + #endregion #region CellErrorStyle Property - public static readonly DependencyProperty CellErrorStyleProperty = - DataGridControl.CellErrorStyleProperty.AddOwner( typeof( ColumnBase ) ); + public static readonly DependencyProperty CellErrorStyleProperty = DataGridControl.CellErrorStyleProperty.AddOwner( typeof( ColumnBase ) ); public Style CellErrorStyle { @@ -976,18 +986,15 @@ namespace Xceed.Wpf.DataGrid } } - #endregion CellErrorStyle Property + #endregion #region CanBeCurrentWhenReadOnly Property - internal event EventHandler CanBeCurrentWhenReadOnlyChanged; - - public static readonly DependencyProperty CanBeCurrentWhenReadOnlyProperty = - DependencyProperty.Register( + public static readonly DependencyProperty CanBeCurrentWhenReadOnlyProperty = DependencyProperty.Register( "CanBeCurrentWhenReadOnly", typeof( bool ), typeof( ColumnBase ), - new FrameworkPropertyMetadata( ( bool )true, new PropertyChangedCallback( ColumnBase.OnCanBeCurrentWhenReadOnlyChanged ) ) ); + new FrameworkPropertyMetadata( true ) ); public bool CanBeCurrentWhenReadOnly { @@ -1001,20 +1008,7 @@ namespace Xceed.Wpf.DataGrid } } - private static void OnCanBeCurrentWhenReadOnlyChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) - { - ColumnBase column = sender as ColumnBase; - - if( column == null ) - return; - - if( column.CanBeCurrentWhenReadOnlyChanged != null ) - { - column.CanBeCurrentWhenReadOnlyChanged( sender, EventArgs.Empty ); - } - } - - #endregion CanBeCurrentWhenReadOnly + #endregion #region HasValidationError Property @@ -1044,12 +1038,12 @@ namespace Xceed.Wpf.DataGrid } else { - this.SetValue( ColumnBase.HasValidationErrorPropertyKey, DependencyProperty.UnsetValue ); + this.ClearValue( ColumnBase.HasValidationErrorPropertyKey ); } } } - #endregion HasValidationError Property + #endregion #region SortDirection Property @@ -1073,7 +1067,7 @@ namespace Xceed.Wpf.DataGrid { if( value == SortDirection.None ) { - this.SetValue( ColumnBase.SortDirectionPropertyKey, DependencyProperty.UnsetValue ); + this.ClearValue( ColumnBase.SortDirectionPropertyKey ); } else { @@ -1081,7 +1075,38 @@ namespace Xceed.Wpf.DataGrid } } - #endregion SortDirection Property + #endregion + + #region SortDirectionCycle Property + + private static readonly SortDirectionCycleCollection DefaultSortDirectionCycle = new SortDirectionCycleCollection( + new ReadOnlyCollection( + new List() + { + SortDirection.Ascending, + SortDirection.Descending, + SortDirection.None, + } ) ); + + public static readonly DependencyProperty SortDirectionCycleProperty = DependencyProperty.Register( + "SortDirectionCycle", + typeof( SortDirectionCycleCollection ), + typeof( ColumnBase ), + new PropertyMetadata( ColumnBase.DefaultSortDirectionCycle ) ); + + public SortDirectionCycleCollection SortDirectionCycle + { + get + { + return ( SortDirectionCycleCollection )this.GetValue( ColumnBase.SortDirectionCycleProperty ); + } + set + { + this.SetValue( ColumnBase.SortDirectionCycleProperty, value ); + } + } + + #endregion #region SortIndex Read-Only Property @@ -1105,7 +1130,7 @@ namespace Xceed.Wpf.DataGrid { if( value == -1 ) { - this.SetValue( ColumnBase.SortIndexPropertyKey, DependencyProperty.UnsetValue ); + this.ClearValue( ColumnBase.SortIndexPropertyKey ); } else { @@ -1113,12 +1138,15 @@ namespace Xceed.Wpf.DataGrid } } - #endregion SortIndex Read-Only Property + #endregion #region GroupDescription Property - public static readonly DependencyProperty GroupDescriptionProperty = - DependencyProperty.Register( "GroupDescription", typeof( GroupDescription ), typeof( ColumnBase ), new UIPropertyMetadata( null ) ); + public static readonly DependencyProperty GroupDescriptionProperty = DependencyProperty.Register( + "GroupDescription", + typeof( GroupDescription ), + typeof( ColumnBase ), + new UIPropertyMetadata( null ) ); public GroupDescription GroupDescription { @@ -1132,12 +1160,15 @@ namespace Xceed.Wpf.DataGrid } } - #endregion GroupDescription Property + #endregion #region GroupConfiguration Property - public static readonly DependencyProperty GroupConfigurationProperty = - DependencyProperty.Register( "GroupConfiguration", typeof( GroupConfiguration ), typeof( ColumnBase ), new UIPropertyMetadata( null ) ); + public static readonly DependencyProperty GroupConfigurationProperty = DependencyProperty.Register( + "GroupConfiguration", + typeof( GroupConfiguration ), + typeof( ColumnBase ), + new UIPropertyMetadata( null ) ); public GroupConfiguration GroupConfiguration { @@ -1151,18 +1182,15 @@ namespace Xceed.Wpf.DataGrid } } - #endregion GroupConfiguration Property + #endregion #region IsMainColumn Property - private Nullable m_isMainColumn = null; - public virtual bool IsMainColumn { get { - ColumnCollection containingCollection = this.ContainingCollection; - + var containingCollection = this.ContainingCollection; if( containingCollection == null ) return ( m_isMainColumn.HasValue ? m_isMainColumn.Value : false ); @@ -1170,42 +1198,41 @@ namespace Xceed.Wpf.DataGrid } set { - this.SetIsMainColumnInternal( value ); - } - } - - internal virtual void SetIsMainColumnInternal( bool value ) - { - ColumnCollection containingCollection = this.ContainingCollection; - - if( containingCollection == null ) - { - if( ( !m_isMainColumn.HasValue ) || ( m_isMainColumn.Value != value ) ) + var containingCollection = this.ContainingCollection; + if( containingCollection == null ) { + if( m_isMainColumn == value ) + return; + m_isMainColumn = value; - this.OnPropertyChanged( new PropertyChangedEventArgs( "IsMainColumn" ) ); - } - } - else - { - ColumnBase oldMainColumn = containingCollection.MainColumn; - if( oldMainColumn != this ) + this.RaiseIsMainColumnChanged(); + } + else if( value ) { containingCollection.MainColumn = this; - // These two PropertyChanged are done in this order to be consistent with - // the events' order when adding a Column already "IsMainColumn". - this.OnPropertyChanged( new PropertyChangedEventArgs( "IsMainColumn" ) ); + } + else + { + if( containingCollection.MainColumn != this ) + return; - if( oldMainColumn != null ) - { - oldMainColumn.OnPropertyChanged( new PropertyChangedEventArgs( "IsMainColumn" ) ); - } + containingCollection.MainColumn = null; } } } - #endregion IsMainColumn Property + internal void RaiseIsMainColumnChanged() + { + this.RefreshDraggableStatus(); + this.OnPropertyChanged( new PropertyChangedEventArgs( ColumnBase.IsMainColumnPropertyName ) ); + } + + internal static readonly string IsMainColumnPropertyName = PropertyHelper.GetPropertyName( ( ColumnBase c ) => c.IsMainColumn ); + + private Nullable m_isMainColumn = null; + + #endregion #region ReadOnly Property @@ -1249,7 +1276,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion OverrideReadOnlyForInsertion Property + #endregion #region PreviousVisibleColumn Property @@ -1262,9 +1289,9 @@ namespace Xceed.Wpf.DataGrid if( this.DataGridControl == null ) return null; - var columnsByVisiblePosition = - ( this.ParentDetailConfiguration != null ) ? this.ParentDetailConfiguration.ColumnsByVisiblePosition : this.DataGridControl.ColumnsByVisiblePosition; - + var columnsByVisiblePosition = ( this.ParentDetailConfiguration != null ) + ? this.ParentDetailConfiguration.ColumnsByVisiblePosition + : this.DataGridControl.ColumnsByVisiblePosition; var previousColumnNode = columnsByVisiblePosition.Find( this ).Previous; while( previousColumnNode != null ) @@ -1283,9 +1310,11 @@ namespace Xceed.Wpf.DataGrid internal void InvalidatePreviousVisibleColumnProperty() { - this.OnPropertyChanged( new PropertyChangedEventArgs( "PreviousVisibleColumn" ) ); + this.OnPropertyChanged( new PropertyChangedEventArgs( ColumnBase.PreviousVisibleColumnPropertyName ) ); } + internal static readonly string PreviousVisibleColumnPropertyName = PropertyHelper.GetPropertyName( ( ColumnBase c ) => c.PreviousVisibleColumn ); + #endregion #region NextVisibleColumn Property @@ -1298,8 +1327,9 @@ namespace Xceed.Wpf.DataGrid if( this.DataGridControl == null ) return null; - var columnsByVisiblePosition = - ( this.ParentDetailConfiguration != null ) ? this.ParentDetailConfiguration.ColumnsByVisiblePosition : this.DataGridControl.ColumnsByVisiblePosition; + var columnsByVisiblePosition = ( this.ParentDetailConfiguration != null ) + ? this.ParentDetailConfiguration.ColumnsByVisiblePosition + : this.DataGridControl.ColumnsByVisiblePosition; var nextColumnNode = columnsByVisiblePosition.Find( this ); @@ -1357,7 +1387,7 @@ namespace Xceed.Wpf.DataGrid return defaultCellRecyclingGroup; } - #endregion CellRecyclingGroup Property + #endregion #region DefaultCellRecyclingGroupDataType Internal Property @@ -1382,7 +1412,7 @@ namespace Xceed.Wpf.DataGrid private Type m_defaultCellRecyclingGroupDataType = typeof( object ); - #endregion DefaultCellRecyclingGroupDataType Internal Property + #endregion #region DefaultCellRecyclingGroup Private Property @@ -1413,20 +1443,14 @@ namespace Xceed.Wpf.DataGrid private object m_defaultCellRecyclingGroup; - #endregion DefaultCellRecyclingGroup Private Property + #endregion #region CurrentRowInEditionCellState Property internal CellState CurrentRowInEditionCellState { - get - { - return m_currentRowInEditionCellState; - } - set - { - m_currentRowInEditionCellState = value; - } + get; + set; } #endregion @@ -1464,10 +1488,10 @@ namespace Xceed.Wpf.DataGrid #region DefaultCulture Property public static readonly DependencyProperty DefaultCultureProperty = DependencyProperty.Register( - "DefaultCulture", - typeof( CultureInfo ), - typeof( ColumnBase ), - new UIPropertyMetadata( CultureInfo.CurrentCulture ) ); + "DefaultCulture", + typeof( CultureInfo ), + typeof( ColumnBase ), + new FrameworkPropertyMetadata( CultureInfo.CurrentCulture ) ); public CultureInfo DefaultCulture { @@ -1483,6 +1507,48 @@ namespace Xceed.Wpf.DataGrid #endregion + #region DraggableStatus Property + + public static readonly DependencyProperty DraggableStatusProperty = DependencyProperty.Register( + "DraggableStatus", + typeof( ColumnDraggableStatus ), + typeof( ColumnBase ), + new UIPropertyMetadata( ColumnDraggableStatus.Draggable, null, new CoerceValueCallback( ColumnBase.CoerceDraggableStatus ) ) ); + + public ColumnDraggableStatus DraggableStatus + { + get + { + return ( ColumnDraggableStatus )this.GetValue( ColumnBase.DraggableStatusProperty ); + } + set + { + this.SetValue( ColumnBase.DraggableStatusProperty, value ); + } + } + + internal void RefreshDraggableStatus() + { + this.CoerceValue( ColumnBase.DraggableStatusProperty ); + } + + private static object CoerceDraggableStatus( DependencyObject sender, object value ) + { + var self = sender as ColumnBase; + var collection = ( self != null ) ? self.ContainingCollection : null; + if( collection == null ) + return value; + + var dataGridControl = collection.DataGridControl; + if( ( dataGridControl == null ) || !dataGridControl.AreDetailsFlatten || !self.IsMainColumn ) + return value; + + // The main column is always locked in first position when details are flatten. + return ColumnDraggableStatus.FirstUndraggable; + } + + #endregion + #region RealizedContainersRequested Event internal event RealizedContainersRequestedEventHandler RealizedContainersRequested; @@ -1491,7 +1557,7 @@ namespace Xceed.Wpf.DataGrid #region ActualWidthChanged Event - internal event ColumnActualWidthChangedHandler ActualWidthChanged; + internal event ColumnActualWidthChangedEventHandler ActualWidthChanged; #endregion @@ -1537,14 +1603,15 @@ namespace Xceed.Wpf.DataGrid public virtual double GetFittedWidth() { var fittedWidth = this.RequestFittedWidth().GetValueOrDefault( -1d ); + var e = new RealizedContainersRequestedEventArgs(); - var eventArgs = new RealizedContainersRequestedEventArgs(); - if( this.RealizedContainersRequested != null ) + var handler = this.RealizedContainersRequested; + if( handler != null ) { - this.RealizedContainersRequested( this, eventArgs ); + handler.Invoke( this, e ); } - var realizedContainers = eventArgs.RealizedContainers; + var realizedContainers = e.RealizedContainers; if( realizedContainers.Count > 0 ) { fittedWidth = Math.Max( fittedWidth, this.GetElementCollectionFittedWidth( realizedContainers ) ); @@ -1553,11 +1620,10 @@ namespace Xceed.Wpf.DataGrid return fittedWidth; } - // Not to be confused with the DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs) !!! This is an overload. - protected virtual void OnPropertyChanged( PropertyChangedEventArgs e ) + protected override void OnPropertyChanged( DependencyPropertyChangedEventArgs e ) { - if( this.PropertyChanged != null ) - this.PropertyChanged( this, e ); + base.OnPropertyChanged( e ); + this.OnPropertyChanged( new PropertyChangedEventArgs( e.Property.Name ) ); } protected override Freezable CreateInstanceCore() @@ -1603,40 +1669,6 @@ namespace Xceed.Wpf.DataGrid this.AttachToContainingCollectionCore( columnCollection ); } - internal void AttachToContainingCollectionCore( ColumnCollection columnCollection ) - { - m_containingCollection = columnCollection; - this.NotifyDataGridControlChanged(); - - this.RealizedContainersRequested += m_containingCollection.OnRealizedContainersRequested; - this.ActualWidthChanged += m_containingCollection.OnActualWidthChanged; - this.DistinctValuesRequested += columnCollection.OnDistinctValuesRequested; - - if( m_isMainColumn.HasValue ) - { - if( m_isMainColumn.Value ) - { - ColumnBase oldMainColumn = columnCollection.MainColumn; - columnCollection.MainColumn = this; - - if( oldMainColumn != null ) - { - oldMainColumn.OnPropertyChanged( new PropertyChangedEventArgs( "IsMainColumn" ) ); - } - // The PropertyChanged of this instance has already been fired before it was added to the collection. - } - - m_isMainColumn = null; - } - else - { - if( columnCollection.Count == 0 ) - { - this.SetIsMainColumnInternal( true ); - } - } - } - internal void DetachFromContainingCollection() { if( m_containingCollection == null ) @@ -1645,61 +1677,13 @@ namespace Xceed.Wpf.DataGrid this.DetachFromContainingCollectionCore(); } - internal void DetachFromContainingCollectionCore() - { - this.RealizedContainersRequested -= m_containingCollection.OnRealizedContainersRequested; - this.ActualWidthChanged -= m_containingCollection.OnActualWidthChanged; - this.DistinctValuesRequested -= m_containingCollection.OnDistinctValuesRequested; - - if( this == m_containingCollection.MainColumn ) - m_containingCollection.MainColumn = null; - - m_containingCollection = null; - this.NotifyDataGridControlChanged(); - } - internal void OnDistinctValuesRequested( object sender, DistinctValuesRequestedEventArgs e ) { - if( this.DistinctValuesRequested != null ) - this.DistinctValuesRequested( this, e ); - } - - internal bool GetIsSettingFixedColumnCount() - { - var detailConfiguration = this.ParentDetailConfiguration; - if( detailConfiguration != null ) - { - return detailConfiguration.IsSettingFixedColumnCount; - } - - return this.DataGridControl.DataGridContext.IsSettingFixedColumnCount; - } - - internal int GetFixedColumnCount() - { - var detailConfiguration = this.ParentDetailConfiguration; - if( detailConfiguration != null ) - { - return ( int )TableView.GetFixedColumnCount( detailConfiguration ); - } - - return ( int )TableView.GetFixedColumnCount( this.DataGridControl.DataGridContext ); - } - - internal void SetFixedColumnCountInfo( FixedColumnUpdateType updateType ) - { - FixedColumnCountInfoEventArgs infoEventArgs = new FixedColumnCountInfoEventArgs( this, updateType ); - - var detailConfiguration = this.ParentDetailConfiguration; - if( detailConfiguration != null ) - { - detailConfiguration.RaiseFixedColumnCountChanged( infoEventArgs ); + var handler = this.DistinctValuesRequested; + if( handler == null ) return; - } - TableViewColumnVirtualizationManagerBase columnVirtualizationManager = - this.DataGridControl.DataGridContext.ColumnVirtualizationManager as TableViewColumnVirtualizationManagerBase; - columnVirtualizationManager.UpdateFixedColumnCountInfo( infoEventArgs ); + handler.Invoke( this, e ); } internal CultureInfo GetCulture( CultureInfo value ) @@ -1719,6 +1703,21 @@ namespace Xceed.Wpf.DataGrid return CultureInfo.CurrentCulture; } + private void AttachToContainingCollectionCore( ColumnCollection columnCollection ) + { + m_containingCollection = columnCollection; + m_isMainColumn = null; + + this.NotifyDataGridControlChanged(); + } + + private void DetachFromContainingCollectionCore() + { + m_containingCollection = null; + + this.NotifyDataGridControlChanged(); + } + private double GetElementCollectionFittedWidth( IEnumerable collection ) { if( collection == null ) @@ -1730,12 +1729,10 @@ namespace Xceed.Wpf.DataGrid foreach( object item in collection ) { - Row row = item as Row; - + var row = item as Row; if( row == null ) { - HeaderFooterItem headerFooter = item as HeaderFooterItem; - + var headerFooter = item as HeaderFooterItem; if( headerFooter != null ) { row = headerFooter.AsVisual() as Row; @@ -1754,25 +1751,28 @@ namespace Xceed.Wpf.DataGrid private bool TryGetCellFittedWidth( Row row, out double fittedWidth ) { - fittedWidth = -1; + fittedWidth = -1d; if( row == null ) return false; Cell cell; - CellCollection cells = row.Cells; - VirtualizingCellCollection virtualCells = cells as VirtualizingCellCollection; + var cells = row.Cells; + var virtualCells = cells as VirtualizingCellCollection; bool releaseCell = false; if( virtualCells != null ) { - if( !virtualCells.TryGetCell( this, out cell ) ) + if( !virtualCells.TryGetBindedCell( this, out cell ) ) { releaseCell = true; cell = virtualCells[ this ]; - Debug.Assert( cell != null ); + if( cell == null ) + return false; + // A created cell doesn't have a template applied yet. + // The call to Cell.GetFittedWidth will fail unless we force the creation of the child element by measuring the cell. if( !cell.IsMeasureValid ) { cell.Measure( Size.Empty ); @@ -1787,8 +1787,7 @@ namespace Xceed.Wpf.DataGrid Debug.Assert( cell != null ); fittedWidth = cell.GetFittedWidth(); - // A cell that was created or recycled to calculate the fitted width must be released - // in order to minimize the number of cells created overall. + // A cell that was created or recycled to calculate the fitted width must be released in order to minimize the number of cells created overall. if( releaseCell ) { Debug.Assert( virtualCells != null ); @@ -1798,89 +1797,37 @@ namespace Xceed.Wpf.DataGrid return true; } - private void SetIsSettingFixedColumnCount() - { - var detailConfiguration = this.ParentDetailConfiguration; - if( detailConfiguration != null ) - { - detailConfiguration.IsSettingFixedColumnCount = true; - return; - } - - this.DataGridControl.DataGridContext.IsSettingFixedColumnCount = true; - } - - private void SetFixedColumnCountInfo() - { - FixedColumnUpdateType updateType; - if( this.Visible ) - { - updateType = FixedColumnUpdateType.Show; - } - else - { - updateType = FixedColumnUpdateType.Hide; - } + #region INotifyPropertyChanged Members - this.SetFixedColumnCountInfo( updateType ); - } + public event PropertyChangedEventHandler PropertyChanged; - private static void OnCellContentStringFormatChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) + protected virtual void OnPropertyChanged( PropertyChangedEventArgs e ) { - ColumnBase column = ( ColumnBase )sender; - - if( string.IsNullOrEmpty( ( string )e.OldValue ) && string.IsNullOrEmpty( ( string )e.NewValue ) ) + var handler = this.PropertyChanged; + if( handler == null ) return; - if( column.CellContentStringFormatChanged != null ) - { - column.CellContentStringFormatChanged( sender, EventArgs.Empty ); - } + Debug.Assert( e != null ); + handler.Invoke( this, e ); } - private static void OnCellContentTemplateChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) - { - var column = ( ColumnBase )sender; - - //Make sure cells pertaining to this group are assigned to the correct recycle bin. - //The recycle bin based on the previous key value will be clean up later by the FixedCellPanel, if no other column uses it. - column.ResetDefaultCellRecyclingGroup(); + #endregion - var handler = column.CellContentTemplateChanged; - if( handler != null ) - { - handler.Invoke( column, EventArgs.Empty ); - } - } + #region IWeakEventListener Members - private static void OnCellContentTemplateSelectorChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) + bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) { - var column = ( ColumnBase )sender; - var handler = column.CellContentTemplateChanged; - - if( handler != null ) - { - handler.Invoke( column, EventArgs.Empty ); - } + return this.OnReceiveWeakEvent( managerType, sender, e ); } - #region INotifyPropertyChanged Members - - public event PropertyChangedEventHandler PropertyChanged; - - #endregion INotifyPropertyChanged Members - - #region IWeakEventListener Members - - bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) + protected virtual bool OnReceiveWeakEvent( Type managerType, object sender, EventArgs e ) { return false; } #endregion - private ColumnCollection m_containingCollection; // = null - private CellState m_currentRowInEditionCellState; + #region CellRecyclingGroupKey Private Class private sealed class CellRecyclingGroupKey { @@ -1904,7 +1851,7 @@ namespace Xceed.Wpf.DataGrid public override bool Equals( object obj ) { - CellRecyclingGroupKey key = obj as CellRecyclingGroupKey; + var key = obj as CellRecyclingGroupKey; if( key == null ) return false; @@ -1920,5 +1867,7 @@ namespace Xceed.Wpf.DataGrid private readonly DataTemplate m_contentTemplate; private readonly Type m_dataType; } + + #endregion } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnCollection.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnCollection.cs index a265445e..e599683f 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnCollection.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnCollection.cs @@ -15,28 +15,30 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Collections.Specialized; using System.ComponentModel; -using System.Windows.Threading; -using System.Threading; +using System.Diagnostics; +using Xceed.Wpf.DataGrid.Utils; namespace Xceed.Wpf.DataGrid { - public class ColumnCollection : ObservableCollection + public class ColumnCollection : ObservableColumnCollection { + #region Static Fields + + internal static readonly string MainColumnPropertyName = PropertyHelper.GetPropertyName( ( ColumnCollection c ) => c.MainColumn ); + + #endregion + internal ColumnCollection( DataGridControl dataGridControl, DetailConfiguration parentDetailConfiguration ) - : base() { - this.DataGridControl = dataGridControl; - this.ParentDetailConfiguration = parentDetailConfiguration; + m_dataGridControl = dataGridControl; + m_parentDetailConfiguration = parentDetailConfiguration; } #region MainColumn Property - public ColumnBase MainColumn + public virtual ColumnBase MainColumn { get { @@ -44,31 +46,37 @@ namespace Xceed.Wpf.DataGrid } set { - if( m_mainColumn == value ) + if( value == m_mainColumn ) return; - m_mainColumn = value; - this.OnPropertyChanged( new PropertyChangedEventArgs( "MainColumn" ) ); - } - } + if( ( value != null ) && !this.Contains( value ) ) + throw new ArgumentException( "The column was not found in the collection." ); - private ColumnBase m_mainColumn; + using( this.DeferColumnsUpdate() ) + { + var oldMainColumn = m_mainColumn; + m_mainColumn = value; - #endregion + if( m_mainColumn != null ) + { + m_mainColumn.RaiseIsMainColumnChanged(); + } - #region FieldNameToColumnDictionary Property + if( oldMainColumn != null ) + { + oldMainColumn.RaiseIsMainColumnChanged(); + } + } - internal Dictionary FieldNameToColumnDictionary - { - get - { - return m_fieldNameToColumns; + this.OnPropertyChanged( new PropertyChangedEventArgs( ColumnCollection.MainColumnPropertyName ) ); } } - #endregion FieldNameToColumnDictionary Property + private ColumnBase m_mainColumn; - #region DataGridControl Property + #endregion + + #region DataGridControl Internal Property internal DataGridControl DataGridControl { @@ -78,9 +86,12 @@ namespace Xceed.Wpf.DataGrid } set { + if( value == m_dataGridControl ) + return; + m_dataGridControl = value; - foreach( ColumnBase column in this ) + foreach( var column in this ) { column.NotifyDataGridControlChanged(); } @@ -89,412 +100,190 @@ namespace Xceed.Wpf.DataGrid private DataGridControl m_dataGridControl; - #endregion DataGridControl Property + #endregion - #region ParentDetailConfiguration Property + #region ParentDetailConfiguration Internal Property internal DetailConfiguration ParentDetailConfiguration - { - get; - set; - } - - #endregion ParentDetailConfiguration Property - - #region ProcessingVisibleColumnsUpdate Property - - internal AutoResetFlag ProcessingVisibleColumnsUpdate { get { - return m_processingVisibleColumnsUpdate; + return m_parentDetailConfiguration; } - } - - private readonly AutoResetFlag m_processingVisibleColumnsUpdate = AutoResetFlagFactory.Create(); - - #endregion - - public ColumnBase this[ string fieldName ] - { - get + set { - ColumnBase column = null; - - m_fieldNameToColumns.TryGetValue( fieldName, out column ); - - return column; + m_parentDetailConfiguration = value; } } - #region IsDeferVisibleColumnsUpdate Internal Property - - internal bool IsDeferVisibleColumnsUpdate - { - get - { - return ( m_deferVisibleColumnsUpdateCount > 0 ); - } - } + private DetailConfiguration m_parentDetailConfiguration; #endregion - public IDisposable DeferVisibleColumnsUpdate() - { - return new DeferedColumnsVisibleUpdateDisposable( this ); - } + #region RealizedContainersRequested Internal Event - protected override void RemoveItem( int index ) + internal event RealizedContainersRequestedEventHandler RealizedContainersRequested; + + private void OnRealizedContainersRequested( RealizedContainersRequestedEventArgs e ) { - ColumnBase column = this[ index ]; + var handler = this.RealizedContainersRequested; + if( handler == null ) + return; - if( column != null ) - { - this.UnregisterColumnChangedEvent( column ); + handler.Invoke( this, e ); + } - column.DetachFromContainingCollection(); + #endregion - m_fieldNameToColumns.Remove( column.FieldName ); - } + #region DistinctValuesRequested Internal Event - base.RemoveItem( index ); - } + internal event DistinctValuesRequestedEventHandler DistinctValuesRequested; - protected override void InsertItem( int index, ColumnBase item ) + private void OnDistinctValuesRequested( DistinctValuesRequestedEventArgs e ) { - if( item != null ) - { - if( ( string.IsNullOrEmpty( item.FieldName ) == true ) && ( !DesignerProperties.GetIsInDesignMode( item ) ) ) - throw new ArgumentException( "A column must have a fieldname.", "item" ); - - if( m_fieldNameToColumns.ContainsKey( item.FieldName ) ) - throw new DataGridException( "A column with same field name already exists in collection." ); + var handler = this.DistinctValuesRequested; + if( handler == null ) + return; - m_fieldNameToColumns.Add( item.FieldName, item ); + handler.Invoke( this, e ); + } - item.AttachToContainingCollection( this ); + #endregion - this.RegisterColumnChangedEvent( item ); - } + #region ActualWidthChanged Internal Event - base.InsertItem( index, item ); - } + internal event ColumnActualWidthChangedEventHandler ActualWidthChanged; - protected override void ClearItems() + private void OnActualWidthChanged( ColumnActualWidthChangedEventArgs e ) { - foreach( ColumnBase column in this ) - { - this.UnregisterColumnChangedEvent( column ); - - column.DetachFromContainingCollection(); - } - - m_fieldNameToColumns.Clear(); + var handler = this.ActualWidthChanged; + if( handler == null ) + return; - base.ClearItems(); + handler.Invoke( this, e ); } - protected override void SetItem( int index, ColumnBase item ) - { - if( ( item != null ) && ( string.IsNullOrEmpty( item.FieldName ) == true ) ) - throw new ArgumentException( "A column must have a fieldname.", "item" ); + #endregion - if( m_fieldNameToColumns.ContainsKey( item.FieldName ) ) - throw new DataGridException( "A column with same field name already exists in collection." ); + protected override void OnItemAdding( ColumnBase item ) + { + base.OnItemAdding( item ); - ColumnBase column = this[ index ]; + Debug.Assert( item != null ); - if( ( column != null ) && ( column != item ) ) + if( item.IsMainColumn ) { - this.UnregisterColumnChangedEvent( column ); - - column.DetachFromContainingCollection(); - - m_fieldNameToColumns.Remove( column.FieldName ); + m_nextMainColumn = item; } - if( ( item != null ) && ( column != item ) ) - { - m_fieldNameToColumns.Add( item.FieldName, item ); - - item.AttachToContainingCollection( this ); + item.AttachToContainingCollection( this ); - this.RegisterColumnChangedEvent( item ); - } - - base.SetItem( index, item ); + item.PropertyChanged += new PropertyChangedEventHandler( this.OnColumnPropertyChanged ); + item.RealizedContainersRequested += new RealizedContainersRequestedEventHandler( this.OnColumnRealizedContainersRequested ); + item.ActualWidthChanged += new ColumnActualWidthChangedEventHandler( this.OnColumnActualWidthChanged ); + item.DistinctValuesRequested += new DistinctValuesRequestedEventHandler( this.OnColumnDistinctValuesRequested ); } - protected override void OnCollectionChanged( NotifyCollectionChangedEventArgs e ) + protected override void OnItemAdded( ColumnBase item ) { - if( ( m_columnAdditionMessagesDeferedCount > 0 ) && ( e.Action == NotifyCollectionChangedAction.Add ) && ( e.NewStartingIndex == ( this.Count - e.NewItems.Count ) ) ) - { - if( m_deferedColumnAdditionMessageStartIndex == -1 ) - { - m_deferedColumnAdditionMessageStartIndex = e.NewStartingIndex; - } - - foreach( object item in e.NewItems ) - { - m_deferedColumns.Add( ( ColumnBase )item ); - } - } - else - { - base.OnCollectionChanged( e ); - } - } + base.OnItemAdded( item ); - internal IDisposable DeferColumnAdditionMessages() - { - return new DeferedColumnAdditionMessageDisposable( this ); + this.UpdateMainColumn(); } - internal void NotifyVisibleColumnsUpdating() + protected override void OnItemRemoving( ColumnBase item ) { - if( this.VisibleColumnsUpdating != null ) - { - this.VisibleColumnsUpdating( this, EventArgs.Empty ); - } - } + Debug.Assert( item != null ); - internal event EventHandler VisibleColumnsUpdating; + item.PropertyChanged -= new PropertyChangedEventHandler( this.OnColumnPropertyChanged ); + item.RealizedContainersRequested -= new RealizedContainersRequestedEventHandler( this.OnColumnRealizedContainersRequested ); + item.ActualWidthChanged -= new ColumnActualWidthChangedEventHandler( this.OnColumnActualWidthChanged ); + item.DistinctValuesRequested -= new DistinctValuesRequestedEventHandler( this.OnColumnDistinctValuesRequested ); - internal void DispatchNotifyVisibleColumnsUpdated() - { - //In all cases, make sure the ColumnVitualizationManager is flaged as outdate, but prevent to make updates to FixedCellPanels right away. - this.NotifyVisibleColumnsUpdated( true ); + item.DetachFromContainingCollection(); - //In all cases, make sure we dipatch an operation to update the FixedCellPanels in case the update is not tiggered by other means (e.g. no scrolling, no DataRow in the grid). - if( m_visibleColumnsUpdatedDispatcherOperation == null && m_dataGridControl != null ) - { - ////# Will be null at first in the case of a detail, so process directly - - //This permits less updates = better performance. - m_visibleColumnsUpdatedDispatcherOperation = - m_dataGridControl.Dispatcher.BeginInvoke( DispatcherPriority.Render, new Action( this.NotifyVisibleColumnsUpdated ), false ); - } + base.OnItemRemoving( item ); } - internal event EventHandler VisibleColumnsUpdated; - - internal void OnRealizedContainersRequested( object sender, RealizedContainersRequestedEventArgs e ) + protected override void OnItemRemoved( ColumnBase item ) { - if( this.RealizedContainersRequested != null ) - { - this.RealizedContainersRequested( this, e ); - } - } + base.OnItemRemoved( item ); - internal event RealizedContainersRequestedEventHandler RealizedContainersRequested; + this.UpdateMainColumn(); + } - internal void OnDistinctValuesRequested( object sender, DistinctValuesRequestedEventArgs e ) + private void UpdateMainColumn() { - if( this.DistinctValuesRequested != null ) + switch( this.Count ) { - this.DistinctValuesRequested( this, e ); - } - } + case 0: + this.MainColumn = null; + break; - internal event DistinctValuesRequestedEventHandler DistinctValuesRequested; + case 1: + this.MainColumn = this[ 0 ]; + break; - internal void OnActualWidthChanged( object sender, ColumnActualWidthChangedEventArgs e ) - { - if( this.ActualWidthChanged != null ) - { - this.ActualWidthChanged( this, e ); + default: + { + var column = m_nextMainColumn ?? m_mainColumn; + + m_nextMainColumn = null; + + if( ( column != null ) && this.Contains( column ) ) + { + this.MainColumn = column; + } + else + { + this.MainColumn = null; + } + } + break; } } - internal event ColumnActualWidthChangedHandler ActualWidthChanged; - - internal event EventHandler ColumnVisibilityChanging; - internal event EventHandler ColumnVisibilityChanged; - - private void RegisterColumnChangedEvent( ColumnBase column ) + private IDisposable DeferColumnsUpdate() { - column.PropertyChanged += new PropertyChangedEventHandler( this.OnColumnPropertyChanged ); - column.TitleChanged += new EventHandler( this.OnColumnValueChanged ); - column.VisiblePositionChanging += new EventHandler( this.OnColumnVisibilityChanging ); - column.VisiblePositionChanged += new EventHandler( this.OnColumnValueChanged ); - column.VisiblePositionChanged += new EventHandler( this.OnColumnVisibilityChanged ); - column.VisibleChanged += new EventHandler( this.OnColumnVisibilityChanged ); - } + if( m_parentDetailConfiguration != null ) + return m_parentDetailConfiguration.DeferColumnsUpdate(); - private void UnregisterColumnChangedEvent( ColumnBase column ) - { - column.PropertyChanged -= new PropertyChangedEventHandler( this.OnColumnPropertyChanged ); - column.TitleChanged -= new EventHandler( this.OnColumnValueChanged ); - column.VisiblePositionChanging -= new EventHandler( this.OnColumnVisibilityChanging ); - column.VisiblePositionChanged -= new EventHandler( this.OnColumnValueChanged ); - column.VisiblePositionChanged -= new EventHandler( this.OnColumnVisibilityChanged ); - column.VisibleChanged -= new EventHandler( this.OnColumnVisibilityChanged ); - } + if( m_dataGridControl != null ) + return m_dataGridControl.DeferColumnsUpdate(); - private void OnColumnPropertyChanged( object sender, PropertyChangedEventArgs e ) - { - if( string.IsNullOrEmpty( e.PropertyName ) || e.PropertyName == "IsMainColumn" ) - { - // The ColumnBase.IsMainColumn property impacts the columns visibility when details are flatten. - var dataGridControl = this.DataGridControl; - if( ( dataGridControl != null ) && ( dataGridControl.AreDetailsFlatten ) ) - { - this.OnColumnVisibilityChanged( sender, EventArgs.Empty ); - } - } + return new EmptyDisposable(); } - private void OnColumnVisibilityChanging( object sender, EventArgs e ) + private void OnColumnPropertyChanged( object sender, PropertyChangedEventArgs e ) { - if( this.ColumnVisibilityChanging != null ) - { - this.ColumnVisibilityChanging( this, new WrappedEventEventArgs( sender, e ) ); - } } - private void OnColumnVisibilityChanged( object sender, EventArgs e ) + private void OnColumnRealizedContainersRequested( object sender, RealizedContainersRequestedEventArgs e ) { - if( this.ColumnVisibilityChanged != null ) - { - this.ColumnVisibilityChanged( this, new WrappedEventEventArgs( sender, e ) ); - } + this.OnRealizedContainersRequested( e ); } - private void OnColumnValueChanged( object sender, EventArgs e ) + private void OnColumnDistinctValuesRequested( object sender, DistinctValuesRequestedEventArgs e ) { - ColumnBase column = ( ColumnBase )sender; + this.OnDistinctValuesRequested( e ); } - private void NotifyVisibleColumnsUpdated( bool onlyIncrementFlag ) + private void OnColumnActualWidthChanged( object sender, ColumnActualWidthChangedEventArgs e ) { - if( this.VisibleColumnsUpdated != null ) - { - this.VisibleColumnsUpdated( this, new VisibleColumnsUpdatedEventArgs( onlyIncrementFlag ) ); - } - - //If only updating the flag, don't reset the DispatcherOperation, since if it is still alive, another call will be made which will reset it. - if( onlyIncrementFlag ) - return; - - m_visibleColumnsUpdatedDispatcherOperation = null; + this.OnActualWidthChanged( e ); } - private int m_columnAdditionMessagesDeferedCount = 0; - private int m_deferVisibleColumnsUpdateCount = 0; - private int m_deferedColumnAdditionMessageStartIndex = -1; - private List m_deferedColumns = new List(); - private Dictionary m_fieldNameToColumns = new Dictionary(); // To optimize indexing speed for FieldName - private DispatcherOperation m_visibleColumnsUpdatedDispatcherOperation; - - private sealed class DeferedColumnAdditionMessageDisposable : IDisposable - { - public DeferedColumnAdditionMessageDisposable( ColumnCollection columns ) - { - if( columns == null ) - throw new ArgumentNullException( "columns" ); - - m_columns = columns; - - m_columns.m_columnAdditionMessagesDeferedCount++; - } - - #region IDisposable Members - - public void Dispose() - { - this.Dispose( true ); - GC.SuppressFinalize( this ); - } - - #endregion - - private void Dispose( bool disposing ) - { - m_columns.m_columnAdditionMessagesDeferedCount--; - - if( m_columns.m_columnAdditionMessagesDeferedCount == 0 ) - { - if( m_columns.m_deferedColumns.Count > 0 ) - { - m_columns.OnCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Add, m_columns.m_deferedColumns, m_columns.m_deferedColumnAdditionMessageStartIndex ) ); - } + private ColumnBase m_nextMainColumn; //null - m_columns.m_deferedColumnAdditionMessageStartIndex = -1; - m_columns.m_deferedColumns.Clear(); - } - } + #region EmptyDisposable Private Class - ~DeferedColumnAdditionMessageDisposable() - { - this.Dispose( false ); - } - - private ColumnCollection m_columns; // = null - } - - private sealed class DeferedColumnsVisibleUpdateDisposable : IDisposable + private sealed class EmptyDisposable : IDisposable { - public DeferedColumnsVisibleUpdateDisposable( ColumnCollection columns ) + void IDisposable.Dispose() { - if( columns == null ) - throw new ArgumentNullException( "columns" ); - - m_columns = columns; - - Interlocked.Increment( ref m_columns.m_deferVisibleColumnsUpdateCount ); } - - #region IDisposable Members - - public void Dispose() - { - this.Dispose( true ); - GC.SuppressFinalize( this ); - } - - #endregion - - private void Dispose( bool disposing ) - { - if( Interlocked.Decrement( ref m_columns.m_deferVisibleColumnsUpdateCount ) != 0 ) - return; - - m_columns.OnCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Reset ) ); - } - - ~DeferedColumnsVisibleUpdateDisposable() - { - this.Dispose( false ); - } - - private ColumnCollection m_columns; // = null } - internal class WrappedEventEventArgs : EventArgs - { - public WrappedEventEventArgs( object sender, EventArgs eventArgs ) - { - if( sender == null ) - throw new ArgumentNullException( "sender" ); - - if( eventArgs == null ) - throw new ArgumentNullException( "eventArgs" ); - - this.WrappedSender = sender; - this.WrappedEventArgs = eventArgs; - } - - public object WrappedSender - { - get; - private set; - } - - public object WrappedEventArgs - { - get; - private set; - } - } + #endregion } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnHierarchyManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnHierarchyManager.cs new file mode 100644 index 00000000..0406cdc6 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnHierarchyManager.cs @@ -0,0 +1,2916 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Windows; +using Xceed.Utils.Wpf; + +namespace Xceed.Wpf.DataGrid +{ + internal sealed class ColumnHierarchyManager : IWeakEventListener + { + internal ColumnHierarchyManager( ColumnCollection columns) + { + if( columns == null ) + throw new ArgumentNullException( "columns" ); + + m_columns = columns; + m_visibleColumns = new ReadOnlyColumnCollection( new ObservableColumnCollection() ); + m_columnsByVisiblePosition = new HashedLinkedList(); + + m_model.LayoutChanging += new EventHandler( this.OnViewLayoutChanging ); + m_model.LayoutChanged += new EventHandler( this.OnViewLayoutChanged ); + m_model.StatusChanged += new EventHandler( this.OnViewStatusChanged ); + } + + #region Columns Property + + internal ColumnCollection Columns + { + get + { + return m_columns; + } + } + + private readonly ColumnCollection m_columns; + + #endregion + + #region VisibleColumns Property + + internal ReadOnlyColumnCollection VisibleColumns + { + get + { + return m_visibleColumns; + } + } + + private readonly ReadOnlyColumnCollection m_visibleColumns; + + #endregion + + #region ColumnsByVisiblePosition Property + + internal HashedLinkedList ColumnsByVisiblePosition + { + get + { + return m_columnsByVisiblePosition; + } + } + + private readonly HashedLinkedList m_columnsByVisiblePosition; + + #endregion + + #region IsUpdateDeferred Property + + internal bool IsUpdateDeferred + { + get + { + lock( this.SyncRoot ) + { + return ( m_deferUpdateCount != 0 ); + } + } + } + + #endregion + + #region SyncRoot Private Property + + private object SyncRoot + { + get + { + return m_model; + } + } + + #endregion + + #region LayoutChanging Event + + internal event EventHandler LayoutChanging; + + private void OnLayoutChanging() + { + var handler = this.LayoutChanging; + if( handler == null ) + return; + + handler.Invoke( this, EventArgs.Empty ); + } + + #endregion + + #region LayoutChanged Event + + internal event EventHandler LayoutChanged; + + private void OnLayoutChanged() + { + var handler = this.LayoutChanged; + if( handler == null ) + return; + + handler.Invoke( this, EventArgs.Empty ); + } + + #endregion + + internal void Initialize( DataGridControl dataGridControl ) + { + if( dataGridControl == null ) + throw new ArgumentNullException( "dataGridControl" ); + + if( m_dataGridControl == dataGridControl ) + return; + + if( m_dataGridControl != null ) + throw new InvalidOperationException( "The current object is already initialized." ); + + m_dataGridControl = dataGridControl; + m_columns.DataGridControl = dataGridControl; + + this.PrepareInitialLayout(); + } + + internal void Clear() + { + if( m_dataGridControl == null ) + return; + + this.ClearLayout(); + + m_columns.DataGridControl = null; + + m_dataGridControl = null; + m_desiredFixedColumnCount = null; + m_synchronizeChildColumnNamesWithChildColumns = false; + } + + internal IDisposable DeferUpdate() + { + return this.DeferUpdate( new UpdateOptions() ); + } + + internal IDisposable DeferUpdate( UpdateOptions options ) + { + return new DeferredDisposable( new DeferUpdateState( this, options ) ); + } + + internal ILevelMarkers GetLevelMarkersFor( ColumnCollection collection ) + { + if( collection == null ) + return null; + + var level = int.MinValue; + + if( collection == m_columns ) + { + level = 0; + } + + if( ( level < 0 ) || ( level >= m_model.LevelCount ) ) + return null; + + return this.WrapLevelMarkers( m_model.GetLevelMarkers( level ) ); + } + + internal IColumnLocation GetColumnLocationFor( ColumnBase column ) + { + return ( IColumnLocation )this.WrapLocation( m_model[ column ] ); + } + + internal int GetFixedColumnCount() + { + var levelCount = m_model.LevelCount; + if( levelCount == 0 ) + return 0; + + // Get the top-most level. + var markers = m_model.GetLevelMarkers( levelCount - 1 ); + + var splitterLocation = markers.Splitter; + if( splitterLocation == null ) + return 0; + + var count = 0; + var location = splitterLocation.GetPreviousSiblingOrCousin(); + + // Count the number of visibile columns that are located before the splitter. + while( location != null ) + { + if( location.Type == LocationType.Column ) + { + var columnLocation = ( ColumnHierarchyModel.IColumnLocation )location; + if( columnLocation.Column.Visible ) + { + count++; + } + } + + location = location.GetPreviousSiblingOrCousin(); + } + + return count; + } + + internal void SetFixedColumnCount( int count ) + { + this.Update( new UpdateOptions( count ) ); + } + + private static int ConvertLevelToMergedHeaderIndex( int level, int mergedHeaderCount ) + { + if( level <= 0 ) + throw new ArgumentException( "The level must be greater than or equal to 1.", "level" ); + + if( mergedHeaderCount <= 0 ) + throw new ArgumentException( "The number of merged headers is expected to be greater than or equal to 1.", "mergedHeaderCount" ); + + if( level > mergedHeaderCount ) + throw new ArgumentException( "The level must be less than or equal to the number of merged headers.", "level" ); + + return ( mergedHeaderCount - level ); + } + + private static int ConvertMergedHeaderIndexToLevel( int index, int mergedHeaderCount ) + { + if( index < 0 ) + throw new ArgumentException( "The index must be greater than or equal to zero.", "index" ); + + if( mergedHeaderCount <= 0 ) + throw new ArgumentException( "The number of merged headers is expected to be greater than or equal to 1.", "mergedHeaderCount" ); + + if( index >= mergedHeaderCount ) + throw new ArgumentException( "The index must be less than the number of merged headers.", "index" ); + + return ( mergedHeaderCount - index ); + } + + private void PrepareInitialLayout() + { + Debug.Assert( m_model.LevelCount == 0 ); + + this.RegisterEvents( m_columns ); + + m_model.AddLevel( 0 ); + + this.SetColumnsInView( 0 ); + + this.UpdateLevelsInView(); + this.Update(); + } + + private void ClearLayout() + { + for( int i = m_model.LevelCount - 1; i > 0; i-- ) + { + this.RemoveLevelInView( i ); + } + + Debug.Assert( m_model.LevelCount == 1 ); + + foreach( var column in this.GetColumns( 0 ) ) + { + this.UnregisterEvents( column ); + } + + m_model.RemoveLevel( 0 ); + + Debug.Assert( m_model.LevelCount == 0 ); + + this.UnregisterEvents( m_columns ); + } + + private void Update() + { + this.Update( new UpdateOptions() ); + } + + private void Update( UpdateOptions options ) + { + lock( this.SyncRoot ) + { + try + { + // The current object has not been initialized yet. + if( m_dataGridControl == null ) + return; + + // The update is deferred and must not be applied yet. + if( m_deferUpdateCount != 0 ) + return; + } + finally + { + if( options.DesiredFixedColumnCount.HasValue ) + { + m_desiredFixedColumnCount = Math.Max( 0, options.DesiredFixedColumnCount.Value ); + } + + if( !m_synchronizeChildColumnNamesWithChildColumns && ( options.SynchronizeChildColumnNamesWithChildColumns == true ) ) + { + m_synchronizeChildColumnNamesWithChildColumns = true; + + for( int i = m_model.LevelCount - 1; i > 0; i-- ) + { + foreach( var columnLocation in this.GetColumnsLocation( this.GetLocationsOnLevelFromFirstToLast( i ) ) ) + { + this.SetPosition( columnLocation, columnLocation.Status.Position.SetChildrenTimestamp( this.GetTimestamp() ) ); + } + } + + this.InvalidateLayout(); + } + } + } + + // Prevent reentrancy. + if( m_isApplyingChanges.IsSet ) + return; + + this.UpdateLayout(); + } + + private void UpdateLayout() + { + Debug.Assert( !m_isApplyingChanges.IsSet ); + + if( ( m_positionVersion == m_modelPositionVersion ) && ( m_visibilityVersion == m_modelVisibilityVersion ) && ( m_layoutVersion == m_modelLayoutVersion ) ) + { + // Nothing has changed, so nothing to do. + if( ( !m_desiredFixedColumnCount.HasValue ) || ( m_desiredFixedColumnCount == this.GetFixedColumnCount() ) ) + { + m_desiredFixedColumnCount = null; + + this.ResetTimestamp(); + return; + } + } + + this.OnLayoutChanging(); + + this.ResetMainColumn(); + + while( true ) + { + if( m_positionVersion != m_modelPositionVersion ) + { + m_positionVersion = m_modelPositionVersion; + this.ApplyPosition(); + } + else if( m_visibilityVersion != m_modelVisibilityVersion ) + { + m_visibilityVersion = m_modelVisibilityVersion; + this.ApplyVisibility(); + } + else if( m_desiredFixedColumnCount.HasValue ) + { + var fixedColumnCount = m_desiredFixedColumnCount.Value; + m_desiredFixedColumnCount = null; + + this.ApplyFixedColumnCount( fixedColumnCount ); + } + else if( m_layoutVersion != m_modelLayoutVersion ) + { + m_layoutVersion = m_modelLayoutVersion; + this.ApplyLayout(); + } + else + { + this.ResetTimestamp(); + break; + } + } + + Debug.Assert( m_timestamp == 0u ); + Debug.Assert( !m_desiredFixedColumnCount.HasValue ); + Debug.Assert( m_positionVersion == m_modelPositionVersion ); + Debug.Assert( m_visibilityVersion == m_modelVisibilityVersion ); + Debug.Assert( m_layoutVersion == m_modelLayoutVersion ); + + this.OnLayoutChanged(); + } + + private void ApplyLayout() + { + if( m_isApplyingChanges.IsSet ) + throw new InvalidOperationException( "The columns' layout is already being applied." ); + + using( m_isApplyingChanges.Set() ) + { + for( int i = m_model.LevelCount - 1; i >= 0; i-- ) + { + this.ApplyColumnsLayoutFromView( i ); + + if( i == 0 ) + { + this.SetVisibleColumnsFromView( i, m_visibleColumns, m_columnsByVisiblePosition ); + } + } + } + } + + private void ApplyPosition() + { + if( m_isApplyingChanges.IsSet ) + throw new InvalidOperationException( "The columns' relations are already being applied." ); + + var levelCount = m_model.LevelCount; + if( levelCount <= 0 ) + return; + + using( m_isApplyingChanges.Set() ) + { + this.UpdateLevelsInView(); + } + } + + private void ApplyVisibility() + { + if( m_isApplyingChanges.IsSet ) + throw new InvalidOperationException( "The columns' visibility is already being applied." ); + + var levelCount = m_model.LevelCount; + if( levelCount <= 0 ) + return; + + using( m_isApplyingChanges.Set() ) + { + foreach( var location in this.GetLocationsOnLevel( levelCount - 1 ) ) + { + // We must redo a visibility pass if the layout has changed while applying the visiblity. + if( !this.ApplyColumnsVisibilityFromView( location ) ) + return; + } + } + } + + private void ApplyFixedColumnCount( int count ) + { + Debug.Assert( count >= 0 ); + + // There is no level or the splitter is already at the proper location. + var levelCount = m_model.LevelCount; + if( ( levelCount == 0 ) || ( count == this.GetFixedColumnCount() ) ) + return; + + // Get the top-most level. + var markers = m_model.GetLevelMarkers( levelCount - 1 ); + + var startLocation = markers.Start; + Debug.Assert( startLocation != null ); + Debug.Assert( startLocation.Type == LocationType.Start ); + + var splitterLocation = markers.Splitter; + Debug.Assert( splitterLocation != null ); + Debug.Assert( splitterLocation.Type == LocationType.Splitter ); + + var targetLocation = default( ColumnHierarchyModel.ILocation ); + var moveBefore = false; + + if( count <= 0 ) + { + targetLocation = startLocation; + } + else + { + var remaining = count; + var currentLocation = startLocation; + var found = false; + + while( !found ) + { + currentLocation = currentLocation.GetNextSiblingOrCousin(); + if( currentLocation == null ) + throw new InvalidOperationException( "Unexpected location." ); + + switch( currentLocation.Type ) + { + case LocationType.Column: + { + var column = ( ( ColumnHierarchyModel.IColumnLocation )currentLocation ).Column; + Debug.Assert( column != null ); + + if( column.Visible ) + { + remaining--; + + if( remaining == 0 ) + { + targetLocation = currentLocation; + found = true; + break; + } + } + } + break; + + // The splitter cannot be set past the orphan section. + case LocationType.Orphan: + { + targetLocation = currentLocation; + moveBefore = true; + found = true; + } + break; + } + } + } + + Debug.Assert( targetLocation != null ); + + if( moveBefore ) + { + if( !splitterLocation.CanMoveBefore( targetLocation ) ) + throw new InvalidOperationException( "The fixed-column splitter cannot be moved." ); + + splitterLocation.MoveBefore( targetLocation ); + } + else + { + if( !splitterLocation.CanMoveAfter( targetLocation ) ) + throw new InvalidOperationException( "The fixed-column splitter cannot be moved." ); + + splitterLocation.MoveAfter( targetLocation ); + } + } + + private void ResetStatus() + { + if( ( m_timestamp == 0u ) || ( m_model.LevelCount <= 0 ) ) + return; + + foreach( var location in this.GetLocationsOnLevel( m_model.LevelCount - 1 ) ) + { + this.ResetStatusOnLocation( location ); + } + } + + private void ResetStatusOnLocation( ColumnHierarchyModel.ILocation location ) + { + if( location == null ) + return; + + var columnLocation = location as ColumnHierarchyModel.IColumnLocation; + if( columnLocation != null ) + { + this.SetStatus( columnLocation, new ColumnStatus( ColumnPositionStatus.Default, ColumnVisibilityStatus.Create( columnLocation.Column.Visible ) ) ); + } + + foreach( var childLocation in this.GetChildLocations( location ) ) + { + this.ResetStatusOnLocation( childLocation ); + } + } + + private void InsertLevelInView( int level ) + { + Debug.Assert( ( level > 0 ) && ( level <= m_model.LevelCount ) ); + + m_model.AddLevel( level ); + + this.SetColumnsInView( level ); + } + + private void RemoveLevelInView( int level ) + { + Debug.Assert( ( level > 0 ) && ( level < m_model.LevelCount ) ); + + foreach( var location in this.GetLocationsOnLevel( level ) ) + { + var parentColumnLocation = location.GetParent() as ColumnHierarchyModel.IColumnLocation; + if( parentColumnLocation != null ) + { + this.UpdateVisibility( parentColumnLocation ); + } + + var columnLocation = location as ColumnHierarchyModel.IColumnLocation; + if( columnLocation != null ) + { + this.UnregisterEvents( columnLocation.Column ); + } + } + + m_model.RemoveLevel( level ); + } + + private void UpdateLevelsInView() + { + var levelCount = m_model.LevelCount; + if( levelCount == 0 ) + return; + + if( levelCount > 1 ) + { + var movedLocations = new HashSet(); + var childLocationsToMove = new Queue(); + var parentLocationsToInspect = new Queue(); + var relationsHistory = new List[ levelCount ]; + var relationsHistoryComparer = new ParentChildRelationshipSnapshotComparer(); + + for( int i = 0; i < levelCount; i++ ) + { + relationsHistory[ i ] = new List(); + + foreach( var columnLocation in this.GetColumnsLocation( this.GetLocationsOnLevel( i ) ) ) + { + var positionStatus = columnLocation.Status.Position; + + if( ( positionStatus.ParentTimestamp != 0u ) && ( i < levelCount - 1 ) ) + { + childLocationsToMove.Enqueue( columnLocation ); + } + + if( ( positionStatus.ChildrenTimestamp != 0u ) && ( i > 0 ) ) + { + parentLocationsToInspect.Enqueue( columnLocation ); + + foreach( var childColumnLocation in this.GetColumnsLocation( this.GetChildLocations( columnLocation ) ) ) + { + childLocationsToMove.Enqueue( childColumnLocation ); + } + + var entry = new ParentChildRelationshipSnapshot( columnLocation, positionStatus.ChildrenTimestamp ); + var history = relationsHistory[ i ]; + + // Insert the entries in a specific order to meet the GetChildColumnLocationDestination method needs. + var index = history.BinarySearch( entry, relationsHistoryComparer ); + + if( index < 0 ) + { + index = ~index; + } + + if( index >= history.Count ) + { + history.Add( entry ); + } + else + { + history.Insert( index, entry ); + } + } + } + } + } + + var isAFlattenDetail = ( m_columns.ParentDetailConfiguration != null ) + && ( m_dataGridControl != null ) + && ( m_dataGridControl.AreDetailsFlatten ); + + // Reorder the columns on each level. + for( int i = 0; i < levelCount; i++ ) + { + // Reorder one of the child level. + if( i < levelCount - 1 ) + { + foreach( var parentLocation in this.GetLocationsOnLevel( i + 1 ) ) + { + ColumnLocationOrderer.Reorder( this.GetColumnsLocation( this.GetChildLocationsFromFirstToLast( parentLocation ) ).ToList(), !isAFlattenDetail ); + } + } + // Reorder the top level. + else + { + ColumnLocationOrderer.Reorder( this.GetColumnsLocation( this.GetLocationsOnLevelFromFirstToLast( i ) ).ToList(), !isAFlattenDetail ); + } + } + } + + private Tuple SetColumnsInView( int level ) + { + var columns = m_columns; + var addAny = false; + + Debug.Assert( columns != null ); + + var columnsToRemove = new HashSet( this.GetColumns( level ) ); + + // Add the missing columns into the view. + foreach( var column in columns ) + { + if( !columnsToRemove.Remove( column ) ) + { + var propagation = PropagationMode.None; + + if( level > 0 ) + { + var visibilitySource = DependencyPropertyHelper.GetValueSource( column, ColumnBase.VisibleProperty ); + + propagation = ( visibilitySource.BaseValueSource == BaseValueSource.Default ) ? PropagationMode.BottomUp : PropagationMode.TopDown; + } + + this.AddColumnInView( column, propagation, level ); + addAny = true; + } + } + + var removedAny = false; + + // Remove the columns that should no longer be in the view. + foreach( var column in columnsToRemove ) + { + this.RemoveColumnInView( column ); + removedAny = true; + } + + return new Tuple( addAny, removedAny ); + } + + private void ResetMainColumn() + { + // The main column must only be reset when details are flatten because it impact column positioning. + if( ( m_dataGridControl == null ) || !m_dataGridControl.AreDetailsFlatten ) + return; + + if( m_isApplyingChanges.IsSet ) + throw new InvalidOperationException( "The columns' relations are already being applied." ); + + var levelCount = m_model.LevelCount; + if( levelCount <= 0 ) + return; + + using( m_isApplyingChanges.Set() ) + { + var mainColumn = m_columns.MainColumn; + if( mainColumn != null ) + { + // We must not reset the main column if it was set explicitly. + var mainColumnLocation = m_model[ mainColumn ]; + if( ( mainColumnLocation == null ) || ( mainColumnLocation.Status.Position.MainColumnTimestamp != 0u ) ) + return; + + m_columns.MainColumn = null; + } + } + } + + private ColumnHierarchyModel.IColumnLocation AddColumnInView( ColumnBase column, PropagationMode mode, int level ) + { + Debug.Assert( column != null ); + Debug.Assert( ( level >= 0 ) && ( level < m_model.LevelCount ) ); + + var location = m_model[ column ]; + if( location == null ) + { + var timestamp = this.GetTimestamp(); + var visibilityStatus = ColumnVisibilityStatus.Create( column.Visible, mode, timestamp ); + var positionStatus = ColumnPositionStatus.Default; + + if( level > 0 ) + { + positionStatus = positionStatus.SetChildrenTimestamp( timestamp ); + } + + switch( DependencyPropertyHelper.GetValueSource( column, ColumnBase.VisiblePositionProperty ).BaseValueSource ) + { + case BaseValueSource.Default: + case BaseValueSource.Inherited: + case BaseValueSource.Unknown: + break; + + default: + positionStatus = positionStatus.SetVisiblePositionTimestamp( timestamp ); + break; + } + + var columnStatus = new ColumnStatus( positionStatus, visibilityStatus ); + + location = m_model.Add( column, columnStatus, level ); + Debug.Assert( location != null ); + + this.RegisterEvents( column ); + } + + return location; + } + + private void RemoveColumnInView( ColumnBase column ) + { + Debug.Assert( column != null ); + + var location = m_model[ column ]; + if( location == null ) + return; + + var parentColumnLocation = location.GetParent() as ColumnHierarchyModel.IColumnLocation; + if( parentColumnLocation != null ) + { + this.UpdateVisibility( parentColumnLocation ); + } + + m_model.Remove( column ); + + this.UnregisterEvents( column ); + } + + private ColumnHierarchyModel.IColumnLocation ReplaceColumnInView( ColumnBase oldColumn, ColumnBase newColumn ) + { + Debug.Assert( ( oldColumn != null ) && ( newColumn != null ) ); + + var oldColumnLocation = m_model[ oldColumn ]; + if( ( oldColumn == newColumn ) || ( oldColumnLocation == null ) ) + return oldColumnLocation; + + var newColumnLocation = m_model[ newColumn ]; + if( newColumnLocation == null ) + { + newColumnLocation = this.AddColumnInView( newColumn, PropagationMode.BottomUp, oldColumnLocation.Level ); + Debug.Assert( newColumnLocation != null ); + } + else if( newColumnLocation.Level != oldColumnLocation.Level ) + { + throw new InvalidOperationException( "The replaced column is not on the same level." ); + } + + Debug.Assert( newColumnLocation.CanMoveAfter( oldColumnLocation ) ); + newColumnLocation.MoveAfter( oldColumnLocation ); + + // Update the location timestamp to keep the column under the parent column. + this.SetPosition( newColumnLocation, newColumnLocation.Status.Position.SetLocationTimestamp( this.GetTimestamp() ) ); + this.SetPosition( newColumnLocation, newColumnLocation.Status.Position.SetDraggableStatusTimestamp( this.GetTimestamp() ) ); + + var lastChildColumnLocation = this.GetColumnsLocation( this.GetChildLocationsFromFirstToLast( newColumnLocation ) ).FirstOrDefault(); + var childColumnLocations = this.GetColumnsLocation( this.GetChildLocationsFromFirstToLast( oldColumnLocation ) ).ToList(); + + // Move the columns under the new column and keep them in the same order. + foreach( var childColumnLocation in childColumnLocations ) + { + if( lastChildColumnLocation != null ) + { + Debug.Assert( childColumnLocation.CanMoveAfter( lastChildColumnLocation ) ); + childColumnLocation.MoveAfter( lastChildColumnLocation ); + } + else + { + Debug.Assert( childColumnLocation.CanMoveUnder( newColumnLocation ) ); + childColumnLocation.MoveUnder( newColumnLocation ); + } + + lastChildColumnLocation = childColumnLocation; + } + + // Reserve a timestamp that is going to be used to keep child columns under their new parent column. + // We want that timestamp to be of "lower priority" than any visible position timestamp update + // on the child columns so a reordering may be done. + var locationTimestamp = this.GetTimestamp(); + + // Update the timestamps on the transfered child columns to keep them under their new parent column. + foreach( var entry in ( from childColumnLocation in childColumnLocations + let positionStatus = childColumnLocation.Status.Position + orderby positionStatus.VisiblePositionTimestamp + select new + { + Location = childColumnLocation, + Status = positionStatus + } ) ) + { + var positionStatus = entry.Status.SetLocationTimestamp( locationTimestamp ); + + if( positionStatus.VisiblePositionTimestamp != 0u ) + { + // Since a visible position reordering was scheduled before the parent column was replaced, + // we must update the visible position timestamp to apply the reordering in the same order + // under the new parent column. + positionStatus = positionStatus.SetVisiblePositionTimestamp( this.GetTimestamp() ); + } + + this.SetPosition( entry.Location, positionStatus ); + } + + this.RemoveColumnInView( oldColumn ); + + return newColumnLocation; + } + + private bool MoveChildColumnUnderLocationInView( ColumnHierarchyModel.IColumnLocation location, ColumnHierarchyModel.ILocation pivot ) + { + if( ( location == null ) || ( pivot == null ) ) + return false; + + // The column is already at the proper location. + if( object.Equals( location.GetParent(), pivot ) ) + return false; + + Debug.Assert( location.CanMoveUnder( pivot ) ); + location.MoveUnder( pivot ); + + var positionStatus = location.Status.Position; + if( positionStatus.VisiblePositionTimestamp == 0u ) + { + // Update the child column status to move it at the right place under its new parent location. + this.SetPosition( location, positionStatus.SetVisiblePositionTimestamp( this.GetTimestamp() ) ); + } + + return true; + } + + private ColumnHierarchyModel.ILocation GetChildColumnLocationDestination( ColumnHierarchyModel.IColumnLocation location, IList relationsHistory ) + { + Debug.Assert( location != null ); + Debug.Assert( ( location.Level >= 0 ) && ( location.Level < m_model.LevelCount - 1 ) ); + + + var column = location.Column; + var positionStatus = location.Status.Position; + var orphanLocation = m_model.GetLevelMarkers( location.Level + 1 ).Orphan; + Debug.Assert( orphanLocation != null ); + + var fallbackParentLocation = location.GetParent(); + var fallbackTimestamp = 0u; + + // Since the target column wants to be under a specific column (or orphan), we must consider the new parent location + // as a possible candidate if it is not one already. + if( ( positionStatus.ParentTimestamp != 0u ) || ( positionStatus.LocationTimestamp != 0u ) ) + { + if( positionStatus.ParentTimestamp > positionStatus.LocationTimestamp ) + { + fallbackParentLocation = orphanLocation; + fallbackTimestamp = positionStatus.ParentTimestamp; + } + else + { + + fallbackParentLocation = location.GetParent(); + fallbackTimestamp = positionStatus.LocationTimestamp; + + Debug.Assert( object.Equals( fallbackParentLocation, location.GetParent() ) ); + } + } + + // Figure out if one of the candidates wants the column. + foreach( var relationHistory in relationsHistory ) + { + // Since the fallback parent location wants the column and it has an higher priority than any remaining + // candidates, there is no need to look for a candidate. + if( relationHistory.Timestamp < fallbackTimestamp ) + break; + + // Since the fallback location is the candidate and it does not want the child column anymore, + // the column should become orphan. + if( object.Equals( fallbackParentLocation, relationHistory.Location ) ) + return orphanLocation; + } + + Debug.Assert( fallbackParentLocation != null ); + return fallbackParentLocation; + } + + private void ApplyColumnsLayoutFromView( int level ) + { + var location = this.GetLocationsOnLevelFromFirstToLast( level ).FirstOrDefault(); + var position = 0; + + while( location != null ) + { + var columnLocation = location as ColumnHierarchyModel.IColumnLocation; + if( columnLocation == null ) + { + location = location.GetNextSiblingOrCousin(); + continue; + } + + var parentColumnLocation = columnLocation.GetParent() as ColumnHierarchyModel.IColumnLocation; + var column = columnLocation.Column; + + column.VisiblePosition = position; + + if( position == 0 ) + { + var columns = column.ContainingCollection; + if( columns != null ) + { + if( ( columns.MainColumn == null ) || ( ( m_dataGridControl != null ) && m_dataGridControl.AreDetailsFlatten ) ) + { + columns.MainColumn = column; + } + } + } + + location = location.GetNextSiblingOrCousin(); + position++; + } + } + + private bool ApplyColumnsVisibilityFromView( ColumnHierarchyModel.ILocation location ) + { + Debug.Assert( location != null ); + + var columnLocation = location as ColumnHierarchyModel.IColumnLocation; + var childrenLocation = this.GetChildLocations( location ).ToList(); + var visibilityStatus = this.GetStatus( location ).Visibility; + + // Apply visibility changes top-down. + if( childrenLocation.Count > 0 ) + { + if( visibilityStatus.Mode == PropagationMode.TopDown ) + { + var childVisibilityStatus = visibilityStatus.SetMode( PropagationMode.TopDown ); + + foreach( var childLocation in ( from l in childrenLocation + let cl = l as ColumnHierarchyModel.IColumnLocation + where ( cl != null ) + && ( cl.Status.Visibility.Timestamp <= childVisibilityStatus.Timestamp ) + select cl ) ) + { + this.SetVisibility( childLocation, childVisibilityStatus ); + } + + // The current column will need to query its child column visibility to determine its visibility. + if( columnLocation != null ) + { + this.SetVisibility( columnLocation, visibilityStatus.SetMode( PropagationMode.BottomUp ) ); + } + } + + // Apply the child columns visibility. + foreach( var childLocation in childrenLocation ) + { + // The layout has been modified while we were updating a child column's visibility. + // A new visibility pass must be done. + if( !this.ApplyColumnsVisibilityFromView( childLocation ) ) + return false; + } + + // Refresh the status in case it changed while applying the child columns visibility. + visibilityStatus = this.GetStatus( location ).Visibility; + } + + // Update the current column's visibility based on its children. + if( columnLocation != null ) + { + if( childrenLocation.Count > 0 ) + { + // Make sure the child columns visible state is not dirty because a user did some changes while we were updating + // the child columns visibility. + if( visibilityStatus.Mode == PropagationMode.BottomUp ) + { + // One of the children is not up-to-date. We need redo the visibility pass. + // We return true because the layout is still the same. + if( !childrenLocation.All( l => this.GetStatus( l ).Visibility.Mode == PropagationMode.None ) ) + return true; + + visibilityStatus = ColumnVisibilityStatus.Create( childrenLocation.Any( l => this.GetStatus( l ).Visibility.Visible ) ); + this.SetVisibility( columnLocation, visibilityStatus ); + } + } + else + { + // A merged column must be hidden when it contains no child column. + visibilityStatus = ColumnVisibilityStatus.Create( visibilityStatus.Visible && ( location.Level == 0 ) ); + this.SetVisibility( columnLocation, visibilityStatus ); + } + } + + // A new visibility pass is required when the visibility needs to be progagated. + if( ( visibilityStatus.Mode != PropagationMode.None ) || ( columnLocation == null ) ) + return true; + + var column = columnLocation.Column; + Debug.Assert( column != null ); + + // Nothing to do. + if( column.Visible == visibilityStatus.Visible ) + return true; + + // The layout is no longer the same since the columns is now hidden or displayed. + this.InvalidateLayout(); + + var layoutVersion = m_modelLayoutVersion; + + column.Visible = visibilityStatus.Visible; + + // The versions will be different if the user altered the layout while we were updating the column's visibility. + return ( layoutVersion == m_modelLayoutVersion ); + } + + private void SetVisibleColumnsFromView( int level, ReadOnlyColumnCollection visibleColumns, HashedLinkedList columnsByVisiblePosition ) + { + Debug.Assert( visibleColumns != null ); + Debug.Assert( columnsByVisiblePosition != null ); + + using( visibleColumns.DeferNotifications() ) + { + // Prevent a Reset event for nothing. + if( visibleColumns.Count != 0 ) + { + visibleColumns.InternalClear(); + } + + columnsByVisiblePosition.Clear(); + + foreach( var column in this.GetColumns( this.GetColumnsLocation( this.GetLocationsOnLevelFromFirstToLast( level ) ) ) ) + { + columnsByVisiblePosition.AddLast( column ); + + using( column.InhibitVisiblePositionChanging() ) + { + if( column.Visible ) + { + visibleColumns.InternalAdd( column ); + } + } + } + } + + var firstVisibleColumn = default( ColumnBase ); + var lastVisibleColumn = default( ColumnBase ); + + foreach( var column in columnsByVisiblePosition ) + { + if( column.Visible ) + { + if( firstVisibleColumn == null ) + { + firstVisibleColumn = column; + } + else + { + column.ClearIsFirstVisible(); + } + + if( lastVisibleColumn != null ) + { + lastVisibleColumn.ClearIsLastVisible(); + } + + lastVisibleColumn = column; + } + else + { + column.ClearIsFirstVisible(); + column.ClearIsLastVisible(); + } + } + + if( firstVisibleColumn != null ) + { + firstVisibleColumn.SetIsFirstVisible( true ); + } + + if( lastVisibleColumn != null ) + { + lastVisibleColumn.SetIsLastVisible( true ); + } + } + + private IEnumerable GetLocationsOnLevelFromFirstToLast( int level ) + { + var location = ( ColumnHierarchyModel.ILocation )m_model.GetLevelMarkers( level ).Start; + Debug.Assert( location.GetPreviousSiblingOrCousin() == null ); + + while( location != null ) + { + yield return location; + + location = location.GetNextSiblingOrCousin(); + } + } + + private IEnumerable GetLocationsOnLevelFromLastToFirst( int level ) + { + var location = ( ColumnHierarchyModel.ILocation )m_model.GetLevelMarkers( level ).End; + Debug.Assert( location.GetNextSiblingOrCousin() == null ); + + while( location != null ) + { + yield return location; + + location = location.GetPreviousSiblingOrCousin(); + } + } + + private IEnumerable GetLocationsOnLevel( int level ) + { + return this.GetLocationsOnLevelFromFirstToLast( level ); + } + + private IEnumerable GetChildLocationsFromFirstToLast( ColumnHierarchyModel.ILocation parentLocation ) + { + if( parentLocation != null ) + { + var location = parentLocation.GetFirstChild(); + + while( location != null ) + { + yield return location; + + location = location.GetNextSibling(); + } + } + } + + private IEnumerable GetChildLocationsFromLastToFirst( ColumnHierarchyModel.ILocation parentLocation ) + { + return this.GetChildLocationsFromFirstToLast( parentLocation ).Reverse(); + } + + private IEnumerable GetChildLocations( ColumnHierarchyModel.ILocation parentLocation ) + { + return this.GetChildLocationsFromFirstToLast( parentLocation ); + } + + private IEnumerable GetColumnsLocation( IEnumerable locations ) + { + return ( from location in locations + let columnLocation = location as ColumnHierarchyModel.IColumnLocation + where ( columnLocation != null ) + select columnLocation ); + } + + private IEnumerable GetColumns( IEnumerable locations ) + { + return ( from location in locations + select location.Column ); + } + + private IEnumerable GetColumns( int level ) + { + return this.GetColumns( this.GetColumnsLocation( this.GetLocationsOnLevel( level ) ) ); + } + + private ColumnStatus GetStatus( ColumnHierarchyModel.ILocation location ) + { + var columnLocation = location as ColumnHierarchyModel.IColumnLocation; + if( columnLocation != null ) + return columnLocation.Status; + + return new ColumnStatus( ColumnVisibilityStatus.Create( false ) ); + } + + private void InvalidateLayout() + { + unchecked + { + m_modelLayoutVersion++; + } + } + + private void InvalidatePosition() + { + unchecked + { + m_modelPositionVersion++; + } + } + + private void InvalidateVisibility() + { + unchecked + { + m_modelVisibilityVersion++; + } + } + + private uint GetTimestamp() + { + checked + { + m_timestamp++; + } + + return m_timestamp; + } + + private void ResetTimestamp() + { + if( m_timestamp == 0u ) + return; + + this.ResetStatus(); + + // The position and visibility counter are reset here since a call to ResetStatus may update them. These updates may be safely ignored. + m_positionVersion = m_modelPositionVersion; + m_visibilityVersion = m_modelVisibilityVersion; + + // The counter is reset to lower the chance of an overflow. + m_timestamp = 0u; + } + + private void UpdateVisibility( ColumnHierarchyModel.IColumnLocation location ) + { + if( location == null ) + return; + + // An update is already scheduled. + var visibilityStatus = location.Status.Visibility; + if( visibilityStatus.Mode != PropagationMode.None ) + return; + + this.SetVisibility( location, visibilityStatus.SetMode( PropagationMode.BottomUp ) ); + } + + private void SetVisibility( ColumnHierarchyModel.IColumnLocation location, ColumnVisibilityStatus visibilityStatus ) + { + if( location == null ) + return; + + var status = location.Status; + + this.SetStatus( location, status.SetVisibilityStatus( visibilityStatus ) ); + } + + private void SetPosition( ColumnHierarchyModel.IColumnLocation location, ColumnPositionStatus positionStatus ) + { + if( location == null ) + return; + + var status = location.Status; + + this.SetStatus( location, status.SetPositionStatus( positionStatus ) ); + } + + private void SetStatus( ColumnHierarchyModel.IColumnLocation location, ColumnStatus status ) + { + if( ( location == null ) || object.Equals( location.Status, status ) ) + return; + + location.Status = status; + } + + private ILevelMarkers WrapLevelMarkers( ColumnHierarchyModel.IMarkers markers ) + { + if( markers == null ) + return null; + + return new Markers( this, markers ); + } + + private ILocation WrapLocation( ColumnHierarchyModel.ILocation location ) + { + if( location == null ) + return null; + + if( location.Type == LocationType.Column ) + { + Debug.Assert( location is ColumnHierarchyModel.IColumnLocation ); + return new ColumnLocation( this, ( ColumnHierarchyModel.IColumnLocation )location ); + } + + return new Location( this, location ); + } + + private void RegisterEvents( ColumnCollection collection ) + { + Debug.Assert( collection != null ); + + CollectionChangedEventManager.AddListener( collection, this ); + PropertyChangedEventManager.AddListener( collection, this, string.Empty ); + } + + private void UnregisterEvents( ColumnCollection collection ) + { + Debug.Assert( collection != null ); + + CollectionChangedEventManager.RemoveListener( collection, this ); + PropertyChangedEventManager.RemoveListener( collection, this, string.Empty ); + } + + private void RegisterEvents( ColumnBase column ) + { + Debug.Assert( column != null ); + PropertyChangedEventManager.AddListener( column, this, string.Empty ); + } + + private void UnregisterEvents( ColumnBase column ) + { + Debug.Assert( column != null ); + + PropertyChangedEventManager.RemoveListener( column, this, string.Empty ); + } + + private void OnColumnsChanged( NotifyCollectionChangedEventArgs e ) + { + Debug.Assert( m_model.LevelCount > 0 ); + + var resetFixedRegions = false; + var resetItemContainerGenerator = false; + + switch( e.Action ) + { + case NotifyCollectionChangedAction.Add: + { + var items = e.NewItems; + if( ( items == null ) || ( items.Count <= 0 ) ) + return; + + Debug.Assert( m_model.LevelCount > 0 ); + + // Only reset the fixed headers/footers if columns are at the master level. + resetFixedRegions = ( m_columns.ParentDetailConfiguration == null ); + + foreach( ColumnBase column in items ) + { + this.AddColumnInView( column, PropagationMode.None, 0 ); + } + } + break; + + case NotifyCollectionChangedAction.Remove: + { + var items = e.OldItems; + if( ( items == null ) || ( items.Count <= 0 ) ) + return; + + resetItemContainerGenerator = true; + + foreach( ColumnBase column in items ) + { + this.RemoveColumnInView( column ); + } + } + break; + + case NotifyCollectionChangedAction.Move: + // Nothing to do. + return; + + case NotifyCollectionChangedAction.Replace: + { + var oldItems = e.OldItems; + if( ( oldItems == null ) || ( oldItems.Count <= 0 ) ) + return; + + var newItems = e.NewItems; + if( ( newItems == null ) || ( newItems.Count <= 0 ) ) + return; + + if( newItems.Count != oldItems.Count ) + throw new NotSupportedException(); + + resetItemContainerGenerator = true; + + for( int i = 0; i < oldItems.Count; i++ ) + { + this.ReplaceColumnInView( ( ColumnBase )oldItems[ i ], ( ColumnBase )newItems[ i ] ); + } + } + break; + + case NotifyCollectionChangedAction.Reset: + { + var result = this.SetColumnsInView( 0 ); + resetFixedRegions = result.Item1; + resetItemContainerGenerator = result.Item2; + } + break; + + default: + throw new NotSupportedException(); + } + + this.Update(); + + if( resetFixedRegions ) + { + m_dataGridControl.ResetFixedRegions(); + } + // When a column is removed, we need to clear the generator from every container to avoid problem + // when a new instance of a column with the same field name is reinserted. + else if( resetItemContainerGenerator ) + { + var itemContainerGenerator = m_dataGridControl.CustomItemContainerGenerator; + if( itemContainerGenerator != null ) + { + itemContainerGenerator.RemoveAllAndNotify(); + } + + // Only reset the fixed headers/footers if columns are at the master level. + if( m_columns.ParentDetailConfiguration == null ) + { + m_dataGridControl.ResetFixedRegions(); + } + } + } + + private void OnColumnCollectionPropertyChanged( PropertyChangedEventArgs e ) + { + var mayHaveChanged = string.IsNullOrEmpty( e.PropertyName ); + + if( mayHaveChanged || ( e.PropertyName == ColumnCollection.MainColumnPropertyName ) ) + { + // We don't want to alter the layout while it is being applied. Furthermore, it is most likely the + // new layout that triggered the change notification. + if( !m_isApplyingChanges.IsSet ) + { + // The ColumnCollection.MainColumn (ColumnBase.IsMainColumn) property impacts the columns layout when details are flatten. + if( ( m_dataGridControl != null ) && m_dataGridControl.AreDetailsFlatten ) + { + var mainColumn = m_columns.MainColumn; + var mainColumnLocation = ( mainColumn != null ) ? m_model[ mainColumn ] : null; + + if( mainColumnLocation != null ) + { + Debug.Assert( mainColumnLocation.Level == 0 ); + + var columnsToMove = new Stack(); + columnsToMove.Push( mainColumnLocation.Column ); + + var parentLocation = mainColumnLocation.GetParent(); + while( parentLocation != null ) + { + var parentColumnLocation = parentLocation as ColumnHierarchyModel.IColumnLocation; + if( parentColumnLocation == null ) + { + // The desired main column is under one of the orphan section. + // It is impossible to move the column and its parent to the first location. + columnsToMove.Clear(); + break; + } + + columnsToMove.Push( parentColumnLocation.Column ); + parentLocation = parentLocation.GetParent(); + } + + while( columnsToMove.Count > 0 ) + { + var column = columnsToMove.Pop(); + var columnLocation = m_model[ column ]; + Debug.Assert( columnLocation != null ); + + var pivotLocation = columnLocation; + var previousLocation = ( ColumnHierarchyModel.ILocation )pivotLocation; + + while( previousLocation != null ) + { + if( previousLocation.Type == LocationType.Column ) + { + pivotLocation = ( ColumnHierarchyModel.IColumnLocation )previousLocation; + } + + previousLocation = previousLocation.GetPreviousSibling(); + } + + if( !object.Equals( columnLocation, pivotLocation ) ) + { + Debug.Assert( columnLocation.CanMoveBefore( pivotLocation ) ); + columnLocation.MoveBefore( pivotLocation ); + + this.SetPosition( columnLocation, columnLocation.Status.Position.SetLocationTimestamp( this.GetTimestamp() ) ); + } + } + } + } + } + + this.InvalidateLayout(); + this.Update(); + } + } + + private void OnColumnPropertyChanged( ColumnBase column, PropertyChangedEventArgs e ) + { + var mayHaveChanged = string.IsNullOrEmpty( e.PropertyName ); + var columnLocation = m_model[ column ]; + var needUpdate = false; + + Debug.Assert( columnLocation != null ); + + if( mayHaveChanged || ( e.PropertyName == ColumnBase.VisibleProperty.Name ) ) + { + if( column.Visible != columnLocation.Status.Visibility.Visible ) + { + this.SetVisibility( columnLocation, ColumnVisibilityStatus.Create( column.Visible, PropagationMode.TopDown, this.GetTimestamp() ) ); + } + + needUpdate = true; + } + + if( mayHaveChanged || ( e.PropertyName == ColumnBase.VisiblePositionProperty.Name ) ) + { + this.SetPosition( columnLocation, columnLocation.Status.Position.SetVisiblePositionTimestamp( this.GetTimestamp() ) ); + + // We must invalidate the layout no matter what to make sure the column's visible position is recalculated and reapplied. + this.InvalidateLayout(); + + needUpdate = true; + } + + if( mayHaveChanged || ( e.PropertyName == ColumnBase.DraggableStatusProperty.Name ) ) + { + this.SetPosition( columnLocation, columnLocation.Status.Position.SetDraggableStatusTimestamp( this.GetTimestamp() ) ); + + needUpdate = true; + } + + if( mayHaveChanged || ( e.PropertyName == ColumnBase.IsMainColumnPropertyName ) ) + { + this.SetPosition( columnLocation, columnLocation.Status.Position.SetMainColumnTimestamp( this.GetTimestamp() ) ); + + needUpdate = true; + } + + if( mayHaveChanged) + { + ColumnHierarchyModel parentColumnLocation = null; + + if( !object.Equals( columnLocation.GetParent(), parentColumnLocation ) ) + { + this.SetPosition( columnLocation, columnLocation.Status.Position.SetParentTimestamp( this.GetTimestamp() ) ); + } + + needUpdate = true; + } + + if( needUpdate ) + { + this.Update(); + } + } + + private void OnViewLayoutChanging( object sender, ColumnHierarchyModel.LayoutChangingEventArgs e ) + { + switch( e.Action ) + { + case ColumnHierarchyModel.LayoutChangingAction.ChangingParent: + case ColumnHierarchyModel.LayoutChangingAction.ChangingFirstChild: + case ColumnHierarchyModel.LayoutChangingAction.Removing: + { + var location = e.Location.GetParent() as ColumnHierarchyModel.IColumnLocation; + if( location != null ) + { + this.UpdateVisibility( location ); + } + } + break; + } + + this.InvalidateLayout(); + } + + private void OnViewLayoutChanged( object sender, ColumnHierarchyModel.LayoutChangedEventArgs e ) + { + switch( e.Action ) + { + case ColumnHierarchyModel.LayoutChangedAction.ParentChanged: + case ColumnHierarchyModel.LayoutChangedAction.FirstChildChanged: + { + var location = e.Location.GetParent() as ColumnHierarchyModel.IColumnLocation; + if( location != null ) + { + this.UpdateVisibility( location ); + } + } + break; + } + + this.InvalidateLayout(); + } + + private void OnViewStatusChanged( object sender, ColumnHierarchyModel.StatusChangedEventArgs e ) + { + var oldStatus = e.OldValue; + var oldVisibilityStatus = oldStatus.Visibility; + var oldPositionStatus = oldStatus.Position; + var newStatus = e.NewValue; + var newVisibilityStatus = newStatus.Visibility; + var newPositionStatus = newStatus.Position; + + if( oldVisibilityStatus.Visible != newVisibilityStatus.Visible ) + { + var parentColumnLocation = e.Location.GetParent() as ColumnHierarchyModel.IColumnLocation; + if( parentColumnLocation != null ) + { + this.UpdateVisibility( parentColumnLocation ); + } + + // The layout is no longer the same since a columns is now hidden or displayed. + this.InvalidateLayout(); + } + + if( !object.Equals( oldPositionStatus, newPositionStatus ) ) + { + this.InvalidatePosition(); + } + + this.InvalidateVisibility(); + } + + #region IWeakEventListener Members + + bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) + { + return this.OnReceiveWeakEvent( managerType, sender, e ); + } + + private bool OnReceiveWeakEvent( Type managerType, object sender, EventArgs e ) + { + if( managerType == typeof( CollectionChangedEventManager ) ) + { + Debug.Assert( m_dataGridControl != null, "The current object should be initialized." ); + + var eventArgs = ( NotifyCollectionChangedEventArgs )e; + + if( sender == m_columns ) + { + this.OnColumnsChanged( eventArgs ); + } + } + else if( managerType == typeof( PropertyChangedEventManager ) ) + { + Debug.Assert( m_dataGridControl != null, "The current object should be initialized." ); + + var eventArgs = ( PropertyChangedEventArgs )e; + + if( sender is ColumnBase ) + { + this.OnColumnPropertyChanged( ( ColumnBase )sender, eventArgs ); + } + else if( sender == m_columns ) + { + this.OnColumnCollectionPropertyChanged( eventArgs ); + } + } + else + { + return false; + } + + return true; + } + + #endregion + + private readonly ColumnHierarchyModel m_model = new ColumnHierarchyModel(); + private readonly AutoResetFlag m_isApplyingChanges = AutoResetFlagFactory.Create( true ); + private DataGridControl m_dataGridControl; + private int m_deferUpdateCount; //0 + private int? m_desiredFixedColumnCount; //null + private bool m_synchronizeChildColumnNamesWithChildColumns; //false + private uint m_timestamp; //0 + private int m_modelLayoutVersion; //0 + private int m_modelPositionVersion; //0 + private int m_modelVisibilityVersion; //0 + private int m_layoutVersion; //0 + private int m_positionVersion; //0 + private int m_visibilityVersion; //0 + + #region ILevelMarkers Internal Interface + + internal interface ILevelMarkers + { + ILocation Start + { + get; + } + + ILocation End + { + get; + } + + ILocation Splitter + { + get; + } + + ILocation Orphan + { + get; + } + } + + #endregion + + #region ILocation Internal Interface + + internal interface ILocation + { + LocationType Type + { + get; + } + + ILocation GetParent(); + ILocation GetFirstChild(); + ILocation GetLastChild(); + + ILocation GetPreviousSibling(); + ILocation GetNextSibling(); + + ILocation GetPreviousSiblingOrCousin(); + ILocation GetNextSiblingOrCousin(); + + bool CanMoveBefore( ILocation location ); + bool CanMoveAfter( ILocation location ); + bool CanMoveUnder( ILocation location ); + + void MoveBefore( ILocation location ); + void MoveAfter( ILocation location ); + void MoveUnder( ILocation location ); + } + + #endregion + + #region IColumnLocation Internal Interface + + internal interface IColumnLocation : ILocation + { + ColumnBase Column + { + get; + } + } + + #endregion + + #region UpdateOptions Internal Struct + + internal struct UpdateOptions + { + internal UpdateOptions( int desiredFixedColumnCount ) + { + m_desiredFixedColumnCount = desiredFixedColumnCount; + m_synchronizeChildColumnNamesWithChildColumns = default( bool? ); + } + + internal UpdateOptions( int desiredFixedColumnCount, bool synchronizeChildColumnNamesWithChildColumns ) + { + m_desiredFixedColumnCount = desiredFixedColumnCount; + m_synchronizeChildColumnNamesWithChildColumns = synchronizeChildColumnNamesWithChildColumns; + } + + internal int? DesiredFixedColumnCount + { + get + { + return m_desiredFixedColumnCount; + } + set + { + m_desiredFixedColumnCount = value; + } + } + + internal bool? SynchronizeChildColumnNamesWithChildColumns + { + get + { + return m_synchronizeChildColumnNamesWithChildColumns; + } + set + { + m_synchronizeChildColumnNamesWithChildColumns = value; + } + } + + private int? m_desiredFixedColumnCount; + private bool? m_synchronizeChildColumnNamesWithChildColumns; + } + + #endregion + + #region Markers Private Class + + private sealed class Markers : ILevelMarkers + { + internal Markers( ColumnHierarchyManager owner, ColumnHierarchyModel.IMarkers markers ) + { + Debug.Assert( owner != null ); + Debug.Assert( markers != null ); + + m_owner = owner; + m_markers = markers; + } + + public ILocation Start + { + get + { + return m_owner.WrapLocation( m_markers.Start ); + } + } + + public ILocation End + { + get + { + return m_owner.WrapLocation( m_markers.End ); + } + } + + public ILocation Splitter + { + get + { + return m_owner.WrapLocation( m_markers.Splitter ); + } + } + + public ILocation Orphan + { + get + { + return m_owner.WrapLocation( m_markers.Orphan ); + } + } + + public override int GetHashCode() + { + return m_markers.GetHashCode(); + } + + public override bool Equals( object obj ) + { + var target = obj as Markers; + if( target == null ) + return false; + + return ( m_owner == target.m_owner ) + && ( object.Equals( m_markers, target.m_markers ) ); + } + + private readonly ColumnHierarchyManager m_owner; + private readonly ColumnHierarchyModel.IMarkers m_markers; + } + + #endregion + + #region Location Private Class + + private class Location : ILocation + { + internal Location( ColumnHierarchyManager owner, ColumnHierarchyModel.ILocation location ) + { + Debug.Assert( owner != null ); + Debug.Assert( location != null ); + + m_owner = owner; + m_location = location; + } + + protected ColumnHierarchyManager Owner + { + get + { + return m_owner; + } + } + + protected ColumnHierarchyModel.ILocation LocationCache + { + get + { + return m_location; + } + } + + LocationType ILocation.Type + { + get + { + return m_location.Type; + } + } + + public override int GetHashCode() + { + return m_location.GetHashCode(); + } + + public override bool Equals( object obj ) + { + var target = obj as Location; + if( target == null ) + return false; + + return ( m_owner == target.m_owner ) + && ( object.Equals( m_location, target.m_location ) ); + } + + protected virtual void OnMovedBefore( Location location ) + { + } + + protected virtual void OnMovedAfter( Location location ) + { + } + + protected virtual void OnMovedUnder( Location location ) + { + } + + ILocation ILocation.GetParent() + { + return m_owner.WrapLocation( m_location.GetParent() ); + } + + ILocation ILocation.GetFirstChild() + { + return m_owner.WrapLocation( m_location.GetFirstChild() ); + } + + ILocation ILocation.GetLastChild() + { + var location = m_location.GetFirstChild(); + if( location == null ) + return m_owner.WrapLocation( null ); + + var next = location.GetNextSibling(); + while( next != null ) + { + location = next; + next = next.GetNextSibling(); + } + + return m_owner.WrapLocation( location ); + } + + ILocation ILocation.GetPreviousSibling() + { + return m_owner.WrapLocation( m_location.GetPreviousSibling() ); + } + + ILocation ILocation.GetNextSibling() + { + return m_owner.WrapLocation( m_location.GetNextSibling() ); + } + + ILocation ILocation.GetPreviousSiblingOrCousin() + { + return m_owner.WrapLocation( m_location.GetPreviousSiblingOrCousin() ); + } + + ILocation ILocation.GetNextSiblingOrCousin() + { + return m_owner.WrapLocation( m_location.GetNextSiblingOrCousin() ); + } + + bool ILocation.CanMoveBefore( ILocation location ) + { + var target = location as Location; + if( target == null ) + return false; + + return m_location.CanMoveBefore( target.m_location ); + } + + bool ILocation.CanMoveAfter( ILocation location ) + { + var target = location as Location; + if( target == null ) + return false; + + return m_location.CanMoveAfter( target.m_location ); + } + + bool ILocation.CanMoveUnder( ILocation location ) + { + var target = location as Location; + if( target == null ) + return false; + + return m_location.CanMoveUnder( target.m_location ); + } + + void ILocation.MoveBefore( ILocation location ) + { + Debug.Assert( ( ( ILocation )this ).CanMoveBefore( location ) ); + + var pivot = ( Location )location; + Debug.Assert( pivot != null ); + + m_location.MoveBefore( pivot.m_location ); + this.OnMovedBefore( pivot ); + + m_owner.Update(); + } + + void ILocation.MoveAfter( ILocation location ) + { + Debug.Assert( ( ( ILocation )this ).CanMoveAfter( location ) ); + + var pivot = ( Location )location; + Debug.Assert( pivot != null ); + + m_location.MoveAfter( pivot.m_location ); + this.OnMovedAfter( pivot ); + + m_owner.Update(); + } + + void ILocation.MoveUnder( ILocation location ) + { + Debug.Assert( ( ( ILocation )this ).CanMoveUnder( location ) ); + + var pivot = ( Location )location; + Debug.Assert( pivot != null ); + + m_location.MoveUnder( pivot.m_location ); + this.OnMovedUnder( pivot ); + + m_owner.Update(); + } + + private readonly ColumnHierarchyManager m_owner; + private readonly ColumnHierarchyModel.ILocation m_location; + } + + #endregion + + #region ColumnLocation Private Class + + private sealed class ColumnLocation : Location, IColumnLocation + { + internal ColumnLocation( ColumnHierarchyManager owner, ColumnHierarchyModel.IColumnLocation location ) + : base( owner, location ) + { + } + + private ColumnHierarchyModel.IColumnLocation TargetLocation + { + get + { + return ( ColumnHierarchyModel.IColumnLocation )this.LocationCache; + } + } + + ColumnBase IColumnLocation.Column + { + get + { + return this.TargetLocation.Column; + } + } + + protected override void OnMovedBefore( Location location ) + { + base.OnMovedBefore( location ); + + this.InvalidatePosition(); + } + + protected override void OnMovedAfter( Location location ) + { + base.OnMovedAfter( location ); + + this.InvalidatePosition(); + } + + protected override void OnMovedUnder( Location location ) + { + base.OnMovedUnder( location ); + + this.InvalidatePosition(); + } + + private void InvalidatePosition() + { + var owner = this.Owner; + var columnLocation = this.TargetLocation; + var positionStatus = columnLocation.Status.Position.SetLocationTimestamp( owner.GetTimestamp() ); + + owner.SetPosition( columnLocation, positionStatus ); + } + } + + #endregion + + #region ColumnHierarchyModel Private Class + + private sealed class ColumnHierarchyModel : ColumnHierarchyModel + { + } + + #endregion + + #region ColumnLocationOrderer Private Class + + private static class ColumnLocationOrderer + { + internal static void Reorder( IList locations, bool useDraggableStatus ) + { + if( ColumnLocationOrderer.IsUnchanged( locations ) ) + return; + + var lockedFirst = new List(); + var lockedLast = new List(); + var unlocked = new List(); + + ColumnLocationOrderer.Split( locations, useDraggableStatus, lockedFirst, lockedLast, unlocked ); + + var lockedFirstStartIndex = 0; + var unlockedStartIndex = lockedFirstStartIndex + lockedFirst.Count; + var lockedLastStartIndex = unlockedStartIndex + unlocked.Count; + + ColumnLocationOrderer.Reorder( locations, lockedFirst, lockedFirstStartIndex ); + ColumnLocationOrderer.Reorder( locations, unlocked, unlockedStartIndex ); + ColumnLocationOrderer.Reorder( locations, lockedLast, lockedLastStartIndex ); + + var newOrder = new int[ locations.Count ]; + + lockedFirst.CopyTo( newOrder, lockedFirstStartIndex ); + unlocked.CopyTo( newOrder, unlockedStartIndex ); + lockedLast.CopyTo( newOrder, lockedLastStartIndex ); + + // Move the locations to get them in the desired order. + ColumnLocationOrderer.Apply( locations, newOrder ); + } + + private static void Reorder( IList locations, IList indexes, int startingPosition ) + { + Debug.Assert( locations != null ); + Debug.Assert( indexes != null ); + + var count = indexes.Count; + if( count <= 1 ) + return; + + var positionsStatus = new ColumnPositionStatus[ count ]; + var newOrder = new int[ count ]; + var movableCount = 0; + var reorderCount = 0; + + // Do a pass to check if a reordering is required. + for( int i = 0; i < positionsStatus.Length; i++ ) + { + var index = indexes[ i ]; + var positionStatus = locations[ index ].Status.Position; + + positionsStatus[ i ] = positionStatus; + + if( positionStatus.LocationTimestamp > positionStatus.VisiblePositionTimestamp ) + { + // This location is considered fixed and will not be sorted. + newOrder[ i ] = index; + } + else + { + // This location is considered movable and may be sorted. + newOrder[ i ] = -1; + movableCount++; + + // This location visible position has changed, so we will need to apply + // an algorithm to figure out where to put it. + if( positionStatus.VisiblePositionTimestamp != 0u ) + { + reorderCount++; + } + } + } + + // Nothing to do if all columns stay where they are. + if( ( reorderCount <= 0 ) || ( movableCount <= 1 ) ) + return; + + var visiblePositions = new List( count ); + var slots = new List( movableCount ); + var movables = new List( movableCount ); + var reorder = new List>( reorderCount ); + + // Separate the movable locations that were updated from the ones that were not. + for( int i = 0; i < newOrder.Length; i++ ) + { + visiblePositions.Add( locations[ indexes[ i ] ].Column.VisiblePosition ); + + // This location is fixed. + if( newOrder[ i ] >= 0 ) + continue; + + slots.Add( new Slot( i, startingPosition + i ) ); + + var timestamp = positionsStatus[ i ].VisiblePositionTimestamp; + if( timestamp == 0u ) + { + movables.Add( i ); + } + else + { + reorder.Add( new Tuple( i, timestamp ) ); + } + } + + var comparer = new MovableComparer( slots, visiblePositions ); + + // Reinsert the updated movable locations in a time fashion order into the not updated movable locations. + foreach( var i in ( from item in reorder + orderby item.Item2, item.Item1 + select item.Item1 ) ) + { + // This property is set to help the comparer identify the element the binary search is looking for. + // The algorithm is complex and need more information than the ones provided by the IComparer<>.Compare method. + comparer.LookFor = i; + + var index = movables.BinarySearch( i, comparer ); + if( index < 0 ) + { + index = ~index; + } + + if( index >= movables.Count ) + { + movables.Add( i ); + } + else + { + movables.Insert( index, i ); + } + } + + Debug.Assert( movables.Count == movableCount ); + + // Reinsert the movable locations into the fixed locations. + for( int i = 0; i < movables.Count; i++ ) + { + newOrder[ slots[ i ].Index ] = indexes[ movables[ i ] ]; + } + + // Set the results. + for( int i = 0; i < newOrder.Length; i++ ) + { + indexes[ i ] = newOrder[ i ]; + } + } + + private static void Apply( IList locations, IList indexes ) + { + Debug.Assert( locations != null ); + Debug.Assert( indexes != null ); + Debug.Assert( locations.Count == indexes.Count ); + + for( int i = 0; i < indexes.Count - 1; i++ ) + { + var pivot = locations[ indexes[ i ] ]; + var target = locations[ indexes[ i + 1 ] ]; + var next = pivot.GetNextSibling(); + + while( !object.Equals( next, target ) ) + { + if( ( next == null ) || ( next.Type == LocationType.Column ) ) + { + Debug.Assert( target.CanMoveAfter( pivot ) ); + target.MoveAfter( pivot ); + break; + } + // A splitter may be located between the columns. Make sure not to move the column if it + // is the case or the splitter will go back next to the starting location. + else + { + next = next.GetNextSibling(); + } + } + } + } + + private static bool IsUnchanged( IList locations ) + { + if( ( locations == null ) || ( locations.Count <= 1 ) ) + return true; + + // Do a pass to check if a reordering is required. + foreach( var location in locations ) + { + var positionStatus = location.Status.Position; + + // This location's lock type may have changed, so does its position. + if( ( positionStatus.DraggableStatusTimestamp != 0u ) || ( positionStatus.MainColumnTimestamp != 0u ) ) + return false; + + if( location.Column.DraggableStatus != ColumnDraggableStatus.Draggable ) + { + // This location may have change position, so we will need to apply an algorithm to figure out where to put it. + if( ( positionStatus.LocationTimestamp != 0u ) || ( positionStatus.VisiblePositionTimestamp != 0u ) ) + return false; + } + else + { + // This location is considered fixed and will not be sorted. + if( positionStatus.LocationTimestamp > positionStatus.VisiblePositionTimestamp ) + continue; + + // This location visible position has changed, so we will need to apply + // an algorithm to figure out where to put it. + if( positionStatus.VisiblePositionTimestamp != 0u ) + return false; + } + } + + return true; + } + + private static void Split( IList locations, bool useDraggableStatus, IList lockedFirst, IList lockedLast, IList unlocked ) + { + Debug.Assert( locations != null ); + Debug.Assert( lockedFirst != null ); + Debug.Assert( lockedLast != null ); + Debug.Assert( unlocked != null ); + + for( int i = 0; i < locations.Count; i++ ) + { + var column = locations[ i ].Column; + var draggableStatus = column.DraggableStatus; + + if( useDraggableStatus ) + { + switch( draggableStatus ) + { + case ColumnDraggableStatus.FirstUndraggable: + { + lockedFirst.Add( i ); + } + break; + + case ColumnDraggableStatus.LastUndraggable: + { + lockedLast.Add( i ); + } + break; + + case ColumnDraggableStatus.Draggable: + { + unlocked.Add( i ); + } + break; + + default: + throw new NotImplementedException(); + } + } + else + { + unlocked.Add( i ); + } + } + } + + private sealed class MovableComparer : IComparer + { + private static readonly IComparer SlotComparer = new VisiblePositionComparer(); + + internal MovableComparer( List slots, IList positions ) + { + m_slots = slots; + m_positions = positions; + } + + internal int LookFor + { + set + { + m_lookFor = value; + } + } + + public int Compare( int x, int y ) + { + if( x == m_lookFor ) + { + var xPosition = m_positions[ x ]; + var yPosition = m_positions[ y ]; + + // Since we are using this comparer to reinsert updated locations in time order, + // a visible position that is lesser than any other location should always be inserted before. + if( ( xPosition < yPosition ) ) + return -1; + + // For a visible position that is greater or equal, we must look at the available movables + // slots to insert the column in the slot that is the nearest to the desired target position. + var xSlot = this.FindSlot( xPosition ); + var ySlot = this.FindSlot( yPosition ); + + var compare = xSlot.CompareTo( ySlot ); + if( compare != 0 ) + return compare; + + var position = this.FindPosition( xSlot ); + + // The location is moving toward the end. + if( x < position ) + { + if( y <= position ) + return 1; + + return -1; + } + // The location is moving toward the start. + else if( x > position ) + { + if( y >= position ) + return -1; + + return 1; + } + } + else if( y == m_lookFor ) + { + var xPosition = m_positions[ x ]; + var yPosition = m_positions[ y ]; + + // Since we are using this comparer to reinsert updated locations in time order, + // a visible position that is lesser than any other location should always be inserted before. + if( ( yPosition < xPosition ) ) + return 1; + + // For a visible position that is greater or equal, we must look at the available movables + // slots to insert the column in the slot that is the nearest to the desired target position. + var xSlot = this.FindSlot( xPosition ); + var ySlot = this.FindSlot( yPosition ); + + var compare = xSlot.CompareTo( ySlot ); + if( compare != 0 ) + return compare; + + var position = this.FindPosition( ySlot ); + + // The location is moving toward the end. + if( y < position ) + { + if( x <= position ) + return -1; + + return 1; + } + // The location is moving toward the start. + else if( y > position ) + { + if( x >= position ) + return 1; + + return -1; + } + } + + return x.CompareTo( y ); + } + + private int FindSlot( int position ) + { + var index = m_slots.BinarySearch( new Slot( 0, position ), MovableComparer.SlotComparer ); + if( index < 0 ) + return ~index; + + return index; + } + + private int FindPosition( int slot ) + { + Debug.Assert( ( slot >= 0 ) && ( slot <= m_slots.Count ) ); + + if( slot >= m_slots.Count ) + return m_slots.Last().Index + 1; + + return m_slots[ slot ].Index; + } + + private readonly List m_slots; + private readonly IList m_positions; + private int m_lookFor; + + private sealed class VisiblePositionComparer : IComparer + { + public int Compare( Slot x, Slot y ) + { + return x.VisiblePosition.CompareTo( y.VisiblePosition ); + } + } + } + + private struct Slot + { + internal Slot( int index, int visiblePosition ) + { + Debug.Assert( index >= 0 ); + Debug.Assert( visiblePosition >= 0 ); + + this.Index = index; + this.VisiblePosition = visiblePosition; + } + + internal readonly int Index; + internal readonly int VisiblePosition; + } + } + + #endregion + + #region DeferUpdateState Private Class + + private sealed class DeferUpdateState : DeferredDisposableState + { + internal DeferUpdateState( ColumnHierarchyManager target, UpdateOptions options ) + { + if( target == null ) + throw new ArgumentNullException( "target" ); + + m_target = target; + m_options = options; + } + + protected override object SyncRoot + { + get + { + return m_target.SyncRoot; + } + } + + protected override bool IsDeferred + { + get + { + return ( m_target.m_deferUpdateCount != 0 ); + } + } + + protected override void Increment() + { + m_target.m_deferUpdateCount++; + } + + protected override void Decrement() + { + m_target.m_deferUpdateCount--; + } + + protected override void OnDeferEnded( bool disposing ) + { + if( !disposing ) + return; + + m_target.Update( m_options ); + } + + private readonly ColumnHierarchyManager m_target; + private readonly UpdateOptions m_options; + } + + #endregion + + #region ColumnStatus Private Struct + + private struct ColumnStatus + { + internal ColumnStatus( ColumnVisibilityStatus visibility ) + : this( default( ColumnPositionStatus ), visibility ) + { + } + + internal ColumnStatus( ColumnPositionStatus position, ColumnVisibilityStatus visibility ) + { + this.Position = position; + this.Visibility = visibility; + } + + internal ColumnStatus SetPositionStatus( ColumnPositionStatus status ) + { + return new ColumnStatus( status, this.Visibility ); + } + + internal ColumnStatus SetVisibilityStatus( ColumnVisibilityStatus status ) + { + return new ColumnStatus( this.Position, status ); + } + + internal readonly ColumnPositionStatus Position; + internal readonly ColumnVisibilityStatus Visibility; + } + + #endregion + + #region ColumnVisibilityStatus Private Struct + + [DebuggerDisplay( "Visible = {Visible}, Mode = {Mode}" )] + private struct ColumnVisibilityStatus + { + private ColumnVisibilityStatus( bool visible, PropagationMode mode, uint timestamp ) + { + m_visible = visible; + m_mode = mode; + m_timestamp = timestamp; + } + + internal ColumnVisibilityStatus SetMode( PropagationMode mode ) + { + return ColumnVisibilityStatus.Create( m_visible, mode, m_timestamp ); + } + + internal bool Visible + { + get + { + return m_visible; + } + } + + internal PropagationMode Mode + { + get + { + return m_mode; + } + } + + internal uint Timestamp + { + get + { + return m_timestamp; + } + } + + internal static ColumnVisibilityStatus Create( bool visible ) + { + return ColumnVisibilityStatus.Create( visible, PropagationMode.None, 0u ); + } + + internal static ColumnVisibilityStatus Create( bool visible, PropagationMode mode, uint timestamp ) + { + return new ColumnVisibilityStatus( visible, mode, timestamp ); + } + + private readonly bool m_visible; + private readonly PropagationMode m_mode; + private readonly uint m_timestamp; + } + + #endregion + + #region ColumnPositionStatus Private Struct + + private struct ColumnPositionStatus + { + internal static readonly ColumnPositionStatus Default = new ColumnPositionStatus(); + + private ColumnPositionStatus( uint parent, uint children, uint visiblePosition, uint location, uint draggableStatus, uint mainColumn ) + { + m_parentTimestamp = parent; + m_childrenTimestamp = children; + m_visiblePositionTimestamp = visiblePosition; + m_locationTimestamp = location; + m_draggableStatusTimestamp = draggableStatus; + m_mainColumnTimestamp = mainColumn; + } + + internal uint ParentTimestamp + { + get + { + return m_parentTimestamp; + } + } + + internal uint ChildrenTimestamp + { + get + { + return m_childrenTimestamp; + } + } + + internal uint VisiblePositionTimestamp + { + get + { + return m_visiblePositionTimestamp; + } + } + + internal uint LocationTimestamp + { + get + { + return m_locationTimestamp; + } + } + + internal uint DraggableStatusTimestamp + { + get + { + return m_draggableStatusTimestamp; + } + } + + internal uint MainColumnTimestamp + { + get + { + return m_mainColumnTimestamp; + } + } + + internal ColumnPositionStatus SetParentTimestamp( uint timestamp ) + { + return new ColumnPositionStatus( timestamp, m_childrenTimestamp, m_visiblePositionTimestamp, m_locationTimestamp, m_draggableStatusTimestamp, m_mainColumnTimestamp ); + } + + internal ColumnPositionStatus SetChildrenTimestamp( uint timestamp ) + { + return new ColumnPositionStatus( m_parentTimestamp, timestamp, m_visiblePositionTimestamp, m_locationTimestamp, m_draggableStatusTimestamp, m_mainColumnTimestamp ); + } + + internal ColumnPositionStatus SetVisiblePositionTimestamp( uint timestamp ) + { + return new ColumnPositionStatus( m_parentTimestamp, m_childrenTimestamp, timestamp, m_locationTimestamp, m_draggableStatusTimestamp, m_mainColumnTimestamp ); + } + + internal ColumnPositionStatus SetLocationTimestamp( uint timestamp ) + { + return new ColumnPositionStatus( m_parentTimestamp, m_childrenTimestamp, m_visiblePositionTimestamp, timestamp, m_draggableStatusTimestamp, m_mainColumnTimestamp ); + } + + internal ColumnPositionStatus SetDraggableStatusTimestamp( uint timestamp ) + { + return new ColumnPositionStatus( m_parentTimestamp, m_childrenTimestamp, m_visiblePositionTimestamp, m_locationTimestamp, timestamp, m_mainColumnTimestamp ); + } + + internal ColumnPositionStatus SetMainColumnTimestamp( uint timestamp ) + { + return new ColumnPositionStatus( m_parentTimestamp, m_childrenTimestamp, m_visiblePositionTimestamp, m_locationTimestamp, m_draggableStatusTimestamp, timestamp ); + } + + private readonly uint m_parentTimestamp; + private readonly uint m_childrenTimestamp; + private readonly uint m_visiblePositionTimestamp; + private readonly uint m_locationTimestamp; + private readonly uint m_draggableStatusTimestamp; + private readonly uint m_mainColumnTimestamp; + } + + #endregion + + #region ParentChildRelationshipSnapshot Private Struct + + private struct ParentChildRelationshipSnapshot + { + internal ParentChildRelationshipSnapshot( ColumnHierarchyModel.IColumnLocation location, uint timestamp ) + { + m_location = location; + m_timestamp = timestamp; + } + + internal ColumnHierarchyModel.IColumnLocation Location + { + get + { + return m_location; + } + } + + internal uint Timestamp + { + get + { + return m_timestamp; + } + } + + private readonly ColumnHierarchyModel.IColumnLocation m_location; + private readonly uint m_timestamp; + } + + #endregion + + #region ParentChildRelationshipSnapshotComparer Private Class + + private sealed class ParentChildRelationshipSnapshotComparer : IComparer + { + public int Compare( ParentChildRelationshipSnapshot x, ParentChildRelationshipSnapshot y ) + { + var compare = x.Timestamp.CompareTo( y.Timestamp ); + if( compare != 0 ) + return -compare; + + return -string.CompareOrdinal( x.Location.Column.FieldName, y.Location.Column.FieldName ); + } + } + + #endregion + + #region PropagationMode Private Enum + + private enum PropagationMode : byte + { + None = 0, + BottomUp, + TopDown, + } + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnHierarchyManagerHelper.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnHierarchyManagerHelper.cs new file mode 100644 index 00000000..4d538c14 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnHierarchyManagerHelper.cs @@ -0,0 +1,167 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Diagnostics; +using System.Linq; + +namespace Xceed.Wpf.DataGrid +{ + internal static class ColumnHierarchyManagerHelper + { + internal static IDisposable DeferColumnsUpdate( DataGridContext dataGridContext ) + { + Debug.Assert( dataGridContext != null ); + + return dataGridContext.ColumnManager.DeferUpdate(); + } + + internal static IDisposable DeferColumnsUpdate( DetailConfiguration detailConfiguration ) + { + Debug.Assert( detailConfiguration != null ); + + return detailConfiguration.ColumnManager.DeferUpdate(); + } + + internal static bool MoveColumnBefore( DataGridContext dataGridContext, ColumnBase current, ColumnBase next ) + { + Debug.Assert( dataGridContext != null ); + + return ColumnHierarchyManagerHelper.MoveColumnBefore( dataGridContext.ColumnManager, current, next ); + } + + internal static bool MoveColumnBefore( DetailConfiguration detailConfiguration, ColumnBase current, ColumnBase next ) + { + Debug.Assert( detailConfiguration != null ); + + return ColumnHierarchyManagerHelper.MoveColumnBefore( detailConfiguration.ColumnManager, current, next ); + } + + internal static bool MoveColumnAfter( DataGridContext dataGridContext, ColumnBase current, ColumnBase previous ) + { + Debug.Assert( dataGridContext != null ); + + return ColumnHierarchyManagerHelper.MoveColumnAfter( dataGridContext.ColumnManager, current, previous ); + } + + internal static bool MoveColumnAfter( DetailConfiguration detailConfiguration, ColumnBase current, ColumnBase previous ) + { + Debug.Assert( detailConfiguration != null ); + + return ColumnHierarchyManagerHelper.MoveColumnAfter( detailConfiguration.ColumnManager, current, previous ); + } + + internal static bool MoveColumnUnder( DataGridContext dataGridContext, ColumnBase current, ColumnBase parent ) + { + Debug.Assert( dataGridContext != null ); + + return ColumnHierarchyManagerHelper.MoveColumnUnder( dataGridContext.ColumnManager, dataGridContext.Columns, current, parent ); + } + + internal static bool MoveColumnUnder( DetailConfiguration detailConfiguration, ColumnBase current, ColumnBase parent ) + { + Debug.Assert( detailConfiguration != null ); + + return ColumnHierarchyManagerHelper.MoveColumnUnder( detailConfiguration.ColumnManager, detailConfiguration.Columns, current, parent ); + } + + private static bool MoveColumnBefore( ColumnHierarchyManager columnsLayout, ColumnBase current, ColumnBase next ) + { + Debug.Assert( columnsLayout != null ); + + var currentLocation = columnsLayout.GetColumnLocationFor( current ); + if( currentLocation == null ) + return false; + + var pivotLocation = columnsLayout.GetColumnLocationFor( next ); + if( pivotLocation == null ) + return false; + + if( !currentLocation.CanMoveBefore( pivotLocation ) ) + return false; + + currentLocation.MoveBefore( pivotLocation ); + return true; + } + + private static bool MoveColumnAfter( ColumnHierarchyManager columnsLayout, ColumnBase current, ColumnBase previous ) + { + Debug.Assert( columnsLayout != null ); + + var currentLocation = columnsLayout.GetColumnLocationFor( current ); + if( currentLocation == null ) + return false; + + var pivotLocation = columnsLayout.GetColumnLocationFor( previous ); + if( pivotLocation == null ) + return false; + + if( !currentLocation.CanMoveAfter( pivotLocation ) ) + return false; + + currentLocation.MoveAfter( pivotLocation ); + return true; + } + + private static bool MoveColumnUnder( ColumnHierarchyManager columnsLayout, ColumnCollection columns, ColumnBase current, ColumnBase parent ) + { + Debug.Assert( columnsLayout != null ); + + var currentLocation = columnsLayout.GetColumnLocationFor( current ); + if( currentLocation == null ) + return false; + + var pivotLocation = default( ColumnHierarchyManager.ILocation ); + + // Move the column under the orphan section. + if( parent == null ) + { + var columnCollection = current.ContainingCollection; + if( columnCollection == null ) + return false; + + var mergedColumnCollection = default( ColumnCollection ); + + if( columnCollection == columns ) + { + mergedColumnCollection = null; + } + + if( mergedColumnCollection == null ) + return false; + + var levelMarkers = columnsLayout.GetLevelMarkersFor( mergedColumnCollection ); + if( levelMarkers == null ) + return false; + + pivotLocation = levelMarkers.Orphan; + } + else + { + pivotLocation = columnsLayout.GetColumnLocationFor( parent ); + } + + if( pivotLocation == null ) + return false; + + if( !currentLocation.CanMoveUnder( pivotLocation ) ) + return false; + + currentLocation.MoveUnder( pivotLocation ); + return true; + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnHierarchyModel.Generic.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnHierarchyModel.Generic.cs new file mode 100644 index 00000000..2179ed22 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnHierarchyModel.Generic.cs @@ -0,0 +1,3122 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Diagnostics; +using System.Linq; +using Xceed.Utils.Collections; + +namespace Xceed.Wpf.DataGrid +{ + internal class ColumnHierarchyModel where TColumn : class + { + #region Static Fields + + private const int None = -1; + + #endregion + + #region LevelCount Property + + internal int LevelCount + { + get + { + return m_level; + } + } + + #endregion + + #region [] Property + + internal IColumnLocation this[ TColumn column ] + { + get + { + if( object.ReferenceEquals( column, null ) ) + throw new ArgumentNullException( "column" ); + + if( m_capacity <= 0 ) + return null; + + var hashCode = column.GetHashCode(); + var index = this.FindColumn( column, hashCode ); + if( index == ColumnHierarchyModel.None ) + return null; + + var entry = m_columns[ index ]; + return new ColumnLocation( this, entry.Column, entry.HashCode, index ); + } + } + + #endregion + + #region LayoutChanging Event + + internal event EventHandler LayoutChanging; + + private void OnLayoutChanging( LayoutChangingEventArgs e ) + { + var handler = this.LayoutChanging; + if( handler == null ) + return; + + try + { + m_preventLayoutChanged = true; + handler.Invoke( this, e ); + } + finally + { + m_preventLayoutChanged = false; + } + } + + #endregion + + #region LayoutChanged Event + + internal event EventHandler LayoutChanged; + + private void OnLayoutChanged( LayoutChangedEventArgs e ) + { + var handler = this.LayoutChanged; + if( handler == null ) + return; + + try + { + m_preventLayoutChanged = true; + handler.Invoke( this, e ); + } + finally + { + m_preventLayoutChanged = false; + } + } + + #endregion + + #region StatusChanged Event + + internal event EventHandler StatusChanged; + + private void OnStatusChanged( StatusChangedEventArgs e ) + { + var handler = this.StatusChanged; + if( handler == null ) + return; + + try + { + m_preventLayoutChanged = true; + handler.Invoke( this, e ); + } + finally + { + m_preventLayoutChanged = false; + } + } + + #endregion + + internal IMarkers AddLevel( int level ) + { + if( level < 0 ) + throw new ArgumentException( "The level must be greater than or equal to zero.", "level" ); + + if( level > m_level ) + throw new ArgumentException( "Only one level can be inserted at a time.", "level" ); + + if( m_preventLayoutChanged ) + throw new InvalidOperationException( "The layout cannot be updated." ); + + // Resize the array to make space for a new level. + if( ( m_marks == null ) || ( m_marks.Length < m_level + 1 ) ) + { + var currentSize = ( m_marks != null ) ? m_marks.Length : 0; + var desizedSize = ( int )Math.Min( Math.Max( m_level + 1, currentSize * 2L ), int.MaxValue ); + + Array.Resize( ref m_marks, desizedSize ); + Debug.Assert( m_marks != null ); + + for( int i = currentSize; i < m_marks.Length; i++ ) + { + m_marks[ i ] = MarkEntry.Default; + } + + // This should only happen when the array is of size int.MaxValue. Technically, this should never happen. + if( !object.Equals( m_marks.Last(), MarkEntry.Default ) ) + throw new InvalidOperationException( "No more levels could be created." ); + } + + return this.AddLevelCore( level ); + } + + internal void RemoveLevel( int level ) + { + if( level < 0 ) + throw new ArgumentException( "The level must be greater than or equal to zero.", "level" ); + + if( level >= m_level ) + throw new ArgumentException( "The level does not exist.", "level" ); + + if( m_preventLayoutChanged ) + throw new InvalidOperationException( "The layout cannot be updated." ); + + this.RemoveLevelCore( level ); + } + + internal IColumnLocation Add( TColumn column, int level ) + { + return this.Add( column, default( TStatus ), level ); + } + + internal IColumnLocation Add( TColumn column, TStatus status, int level ) + { + if( object.ReferenceEquals( column, null ) ) + throw new ArgumentNullException( "column" ); + + if( level < 0 ) + throw new ArgumentException( "The level must be greater than or equal to zero.", "level" ); + + if( level >= m_level ) + throw new ArgumentException( "The level is not available.", "level" ); + + if( m_preventLayoutChanged ) + throw new InvalidOperationException( "The layout cannot be updated." ); + + var hashCode = column.GetHashCode(); + + if( m_size > 0 ) + { + if( this.FindColumn( column, hashCode ) != ColumnHierarchyModel.None ) + throw new ArgumentException( "The column is already in the collection.", "column" ); + } + + var orphan = this.FindMark( level ).Orphan; + Debug.Assert( orphan != ColumnHierarchyModel.None ); + + var index = this.AddCore( column, status, hashCode ); + var location = new ColumnLocation( this, column, hashCode, index ); + + this.OnLayoutChanged( new LayoutChangedEventArgs( location, LayoutChangedAction.Added ) ); + + if( !object.Equals( status, default( TStatus ) ) ) + { + this.OnStatusChanged( new StatusChangedEventArgs( location, default( TStatus ), status ) ); + } + + this.ConnectBefore( index, orphan ); + + return location; + } + + internal bool Remove( TColumn column ) + { + if( object.ReferenceEquals( column, null ) ) + throw new ArgumentNullException( "column" ); + + if( m_preventLayoutChanged ) + throw new InvalidOperationException( "The layout cannot be updated." ); + + if( m_size <= 0 ) + return false; + + var index = this.FindColumn( column ); + if( index == ColumnHierarchyModel.None ) + return false; + + var level = this.GetLevel( index ); + var relations = m_relations[ index ]; + + // Move all children under the level's orphan entry. + if( relations.FirstChild != ColumnHierarchyModel.None ) + { + var orphan = this.FindMark( level ).Orphan; + Debug.Assert( orphan != ColumnHierarchyModel.None ); + + var current = relations.FirstChild; + var next = this.GetNextSibling( current ); + + Debug.Assert( this.IsColumn( current ) ); + this.Disconnect( current ); + this.ConnectUnder( current, orphan ); + + var previous = current; + current = next; + + while( current != ColumnHierarchyModel.None ) + { + next = this.GetNextSibling( current ); + + Debug.Assert( this.IsColumn( current ) ); + this.Disconnect( current ); + this.ConnectAfter( current, previous ); + + previous = current; + current = next; + } + } + + Debug.Assert( this.GetFirstChild( index ) == ColumnHierarchyModel.None ); + + this.OnLayoutChanging( new LayoutChangingEventArgs( this.GetTargetLocation( index ), LayoutChangingAction.Removing ) ); + this.Disconnect( index ); + this.RemoveCore( index ); + + return true; + } + + internal bool Contains( TColumn column ) + { + if( ( m_size <= 0 ) || object.ReferenceEquals( column, null ) ) + return false; + + return ( this.FindColumn( column ) != ColumnHierarchyModel.None ); + } + + internal void Clear() + { + if( m_preventLayoutChanged ) + throw new InvalidOperationException( "The layout cannot be updated." ); + + if( m_size <= 0 ) + return; + + this.OnLayoutChanging( new LayoutChangingEventArgs( null, LayoutChangingAction.Clearing ) ); + + Debug.Assert( m_buckets != null ); + Debug.Assert( m_columns != null ); + Debug.Assert( m_status != null ); + Debug.Assert( m_relations != null ); + Debug.Assert( m_marks != null ); + + for( int i = 0; i < m_level; i++ ) + { + m_marks[ i ] = MarkEntry.Default; + } + + for( int i = 0; i < m_capacity; i++ ) + { + m_buckets[ i ] = ColumnHierarchyModel.None; + m_columns[ i ] = new ColumnEntry( ( i < m_capacity - 1 ) ? i + 1 : ColumnHierarchyModel.None ); + m_status[ i ] = default( TStatus ); + m_relations[ i ] = RelationEntry.Default; + } + + m_level = 0; + m_free = 0; + m_size = 0; + + this.OnLayoutChanged( new LayoutChangedEventArgs( null, LayoutChangedAction.Cleared ) ); + } + + internal IMarkers GetLevelMarkers( int level ) + { + if( level < 0 ) + throw new ArgumentException( "The level must be greater than or equal to zero.", "level" ); + + if( level >= m_level ) + throw new ArgumentException( "The level must be less than LevelCount.", "level" ); + + var entry = this.FindMark( level ); + + return new Markers( this, level, entry ); + } + + private Markers AddLevelCore( int level ) + { + Debug.Assert( ( level >= 0 ) && ( level <= m_level ) ); + Debug.Assert( m_marks != null ); + Debug.Assert( level < m_marks.Length ); + Debug.Assert( object.Equals( m_marks.Last(), MarkEntry.Default ) ); + + // Offset the marks to insert a entry that will deal with the new level. + for( int i = m_marks.Length - 1; i > level; i-- ) + { + m_marks[ i ] = m_marks[ i - 1 ]; + } + + var start = this.AddCore( default( TStatus ) ); + var end = this.AddCore( default( TStatus ) ); + var splitter = this.AddCore( default( TStatus ) ); + var orphan = this.AddCore( default( TStatus ) ); + var markEntry = new MarkEntry( start, end, splitter, orphan ); + var markers = new Markers( this, level, markEntry ); + + m_marks[ level ] = markEntry; + m_level++; + + this.OnLayoutChanged( new LayoutChangedEventArgs( markers.Start, LayoutChangedAction.Added ) ); + this.OnLayoutChanged( new LayoutChangedEventArgs( markers.End, LayoutChangedAction.Added ) ); + this.OnLayoutChanged( new LayoutChangedEventArgs( markers.Splitter, LayoutChangedAction.Added ) ); + this.OnLayoutChanged( new LayoutChangedEventArgs( markers.Orphan, LayoutChangedAction.Added ) ); + + var parentStart = ColumnHierarchyModel.None; + var parentEnd = ColumnHierarchyModel.None; + var parentSplitter = ColumnHierarchyModel.None; + var parentOrphan = ColumnHierarchyModel.None; + var childStart = ColumnHierarchyModel.None; + var childEnd = ColumnHierarchyModel.None; + var childSplitter = ColumnHierarchyModel.None; + var childOrphan = ColumnHierarchyModel.None; + + if( level + 1 < m_marks.Length ) + { + var entry = m_marks[ level + 1 ]; + + parentStart = entry.Start; + parentEnd = entry.End; + parentSplitter = entry.Splitter; + parentOrphan = entry.Orphan; + } + + if( level > 0 ) + { + var entry = m_marks[ level - 1 ]; + + childStart = entry.Start; + childEnd = entry.End; + childSplitter = entry.Splitter; + childOrphan = entry.Orphan; + } + + // Move the entries on the child level under the new level entries. + if( childStart != ColumnHierarchyModel.None ) + { + Debug.Assert( childStart != ColumnHierarchyModel.None ); + Debug.Assert( childEnd != ColumnHierarchyModel.None ); + Debug.Assert( childSplitter != ColumnHierarchyModel.None ); + Debug.Assert( childOrphan != ColumnHierarchyModel.None ); + Debug.Assert( childOrphan == this.GetPreviousSiblingOrCousin( childEnd ) ); + Debug.Assert( this.GetNextSiblingOrCousin( childEnd ) == ColumnHierarchyModel.None ); + + var next = childOrphan; + var current = this.GetPreviousSiblingOrCousin( next ); + + // Move the child orphan entry under the new level's orphan entry. + this.Disconnect( childOrphan ); + this.ConnectUnder( childOrphan, orphan ); + + // Move the columns under the new level's orphan entry. + while( current != ColumnHierarchyModel.None ) + { + var previous = this.GetPreviousSiblingOrCousin( current ); + + if( this.IsColumn( current ) ) + { + this.Disconnect( current ); + this.ConnectBefore( current, next ); + + next = current; + } + + current = previous; + } + + // Move the remaining marker entries under the new level's related marker entries. + this.Disconnect( childStart ); + this.Disconnect( childEnd ); + this.Disconnect( childSplitter ); + + this.ConnectUnder( childStart, start ); + this.ConnectUnder( childEnd, end ); + this.ConnectUnder( childSplitter, splitter ); + + Debug.Assert( this.GetFirstChild( start ) != ColumnHierarchyModel.None ); + Debug.Assert( this.GetFirstChild( end ) != ColumnHierarchyModel.None ); + Debug.Assert( this.GetFirstChild( splitter ) != ColumnHierarchyModel.None ); + Debug.Assert( this.GetFirstChild( orphan ) != ColumnHierarchyModel.None ); + } + + // Move the new level's marker entries under the parent level's related marker entries. + if( parentStart != ColumnHierarchyModel.None ) + { + Debug.Assert( parentStart != ColumnHierarchyModel.None ); + Debug.Assert( parentEnd != ColumnHierarchyModel.None ); + Debug.Assert( parentSplitter != ColumnHierarchyModel.None ); + Debug.Assert( parentOrphan != ColumnHierarchyModel.None ); + Debug.Assert( parentOrphan == this.GetPreviousSiblingOrCousin( parentEnd ) ); + Debug.Assert( this.GetNextSiblingOrCousin( parentEnd ) == ColumnHierarchyModel.None ); + + Debug.Assert( this.GetFirstChild( parentStart ) == ColumnHierarchyModel.None ); + Debug.Assert( this.GetFirstChild( parentEnd ) == ColumnHierarchyModel.None ); + Debug.Assert( this.GetFirstChild( parentSplitter ) == ColumnHierarchyModel.None ); + Debug.Assert( this.GetFirstChild( parentOrphan ) == ColumnHierarchyModel.None ); + + this.ConnectUnder( start, parentStart ); + this.ConnectUnder( end, parentEnd ); + this.ConnectUnder( splitter, parentSplitter ); + this.ConnectUnder( orphan, parentOrphan ); + } + // Order the new level's marker entries. + else + { + this.ConnectAfter( splitter, start ); + this.ConnectAfter( orphan, splitter ); + this.ConnectAfter( end, orphan ); + } + + return markers; + } + + private void RemoveLevelCore( int level ) + { + var markers = this.FindMark( level ); + var start = markers.Start; + var end = markers.End; + var splitter = markers.Splitter; + var orphan = markers.Orphan; + Debug.Assert( start != ColumnHierarchyModel.None ); + Debug.Assert( end != ColumnHierarchyModel.None ); + Debug.Assert( splitter != ColumnHierarchyModel.None ); + Debug.Assert( orphan != ColumnHierarchyModel.None ); + + var parentStart = ColumnHierarchyModel.None; + var parentEnd = ColumnHierarchyModel.None; + var parentSplitter = ColumnHierarchyModel.None; + var parentOrphan = ColumnHierarchyModel.None; + var childStart = ColumnHierarchyModel.None; + var childEnd = ColumnHierarchyModel.None; + var childSplitter = ColumnHierarchyModel.None; + var childOrphan = ColumnHierarchyModel.None; + + if( level + 1 < m_marks.Length ) + { + var entry = m_marks[ level + 1 ]; + + parentStart = entry.Start; + parentEnd = entry.End; + parentSplitter = entry.Splitter; + parentOrphan = entry.Orphan; + } + + if( level > 0 ) + { + var entry = m_marks[ level - 1 ]; + + childStart = entry.Start; + childEnd = entry.End; + childSplitter = entry.Splitter; + childOrphan = entry.Orphan; + } + + if( childStart != ColumnHierarchyModel.None ) + { + Debug.Assert( childStart != ColumnHierarchyModel.None ); + Debug.Assert( childEnd != ColumnHierarchyModel.None ); + Debug.Assert( childSplitter != ColumnHierarchyModel.None ); + Debug.Assert( childOrphan != ColumnHierarchyModel.None ); + Debug.Assert( childOrphan == this.GetPreviousSiblingOrCousin( childEnd ) ); + Debug.Assert( this.GetNextSiblingOrCousin( childEnd ) == ColumnHierarchyModel.None ); + + // Link all entries on the child level together. They will be rearrange later if necessary. + var next = ColumnHierarchyModel.None; + var current = childEnd; + + while( current != ColumnHierarchyModel.None ) + { + var previous = this.GetPreviousSiblingOrCousin( current ); + + this.Disconnect( current ); + + if( next != ColumnHierarchyModel.None ) + { + this.ConnectBefore( current, next ); + } + else + { + this.SetRelations( current, new RelationEntry( ColumnHierarchyModel.None, this.GetFirstChild( current ), ColumnHierarchyModel.None, ColumnHierarchyModel.None ) ); + } + + next = current; + current = previous; + } + } + + // Remove any relation to entries of the removed level. + { + var current = end; + while( current != ColumnHierarchyModel.None ) + { + var previous = this.GetPreviousSiblingOrCousin( current ); + + this.OnLayoutChanging( new LayoutChangingEventArgs( this.GetTargetLocation( current ), LayoutChangingAction.Removing ) ); + this.Disconnect( current ); + this.RemoveCore( current ); + + current = previous; + } + } + + // Offset the marks to remove the level that was removed. + for( int i = level; i < m_level - 1; i++ ) + { + m_marks[ i ] = m_marks[ i + 1 ]; + } + + m_level--; + m_marks[ m_level ] = MarkEntry.Default; + + // Reconnect the entries on the child level under the parent level's related entries. + if( ( childStart != ColumnHierarchyModel.None ) && ( parentStart != ColumnHierarchyModel.None ) ) + { + Debug.Assert( parentStart != ColumnHierarchyModel.None ); + Debug.Assert( parentEnd != ColumnHierarchyModel.None ); + Debug.Assert( parentSplitter != ColumnHierarchyModel.None ); + Debug.Assert( parentOrphan != ColumnHierarchyModel.None ); + Debug.Assert( parentOrphan == this.GetPreviousSibling( parentEnd ) ); + Debug.Assert( this.GetFirstChild( parentStart ) == ColumnHierarchyModel.None ); + Debug.Assert( this.GetFirstChild( parentEnd ) == ColumnHierarchyModel.None ); + Debug.Assert( this.GetFirstChild( parentSplitter ) == ColumnHierarchyModel.None ); + Debug.Assert( this.GetFirstChild( parentOrphan ) == ColumnHierarchyModel.None ); + Debug.Assert( this.GetNextSiblingOrCousin( parentEnd ) == ColumnHierarchyModel.None ); + + var next = childOrphan; + var current = this.GetPreviousSibling( next ); + + // Move the child orphan entry under the parent level's orphan entry. + this.Disconnect( childOrphan ); + this.ConnectUnder( childOrphan, parentOrphan ); + + // Move the columns under the parent level's orphan entry. + while( current != ColumnHierarchyModel.None ) + { + var previous = this.GetPreviousSibling( current ); + + if( this.IsColumn( current ) ) + { + this.Disconnect( current ); + this.ConnectBefore( current, next ); + + next = current; + } + + current = previous; + } + + // Move the remaining marker entries under the parent level's related marker entries. + this.Disconnect( childStart ); + this.Disconnect( childEnd ); + this.Disconnect( childSplitter ); + + this.ConnectUnder( childStart, parentStart ); + this.ConnectUnder( childEnd, parentEnd ); + this.ConnectUnder( childSplitter, parentSplitter ); + + Debug.Assert( this.GetFirstChild( parentStart ) == childStart ); + Debug.Assert( this.GetFirstChild( parentEnd ) == childEnd ); + Debug.Assert( this.GetFirstChild( parentSplitter ) == childSplitter ); + Debug.Assert( this.GetFirstChild( parentOrphan ) != ColumnHierarchyModel.None ); + } + } + + private int AddCore( TStatus status ) + { + this.EnsureCapacity(); + + Debug.Assert( m_columns != null ); + Debug.Assert( m_status != null ); + Debug.Assert( m_relations != null ); + + var free = m_free; + + m_free = m_columns[ m_free ].Next; + m_columns[ free ] = new ColumnEntry( ColumnHierarchyModel.None ); + m_status[ free ] = status; + m_relations[ free ] = RelationEntry.Default; + + m_size++; + + return free; + } + + private int AddCore( TColumn column, TStatus status, int hashCode ) + { + var index = this.AddCore( status ); + + Debug.Assert( ( index >= 0 ) && ( index < m_capacity ) ); + Debug.Assert( m_buckets != null ); + Debug.Assert( m_columns != null ); + Debug.Assert( m_status != null ); + + var bucket = this.GetBucket( hashCode ); + Debug.Assert( ( bucket >= 0 ) && ( bucket < m_buckets.Length ) ); + + var collision = m_buckets[ bucket ]; + + m_buckets[ bucket ] = index; + m_columns[ index ] = new ColumnEntry( column, hashCode, collision ); + + return index; + } + + private void RemoveCore( int index ) + { + Debug.Assert( m_buckets != null ); + Debug.Assert( m_columns != null ); + Debug.Assert( m_status != null ); + Debug.Assert( m_relations != null ); + Debug.Assert( ( index >= 0 ) && ( index < m_capacity ) ); + + m_status[ index ] = default( TStatus ); + m_relations[ index ] = RelationEntry.Default; + + var entry = m_columns[ index ]; + + // Only column entry needs to adjust the buckets. + if( this.IsColumn( entry ) ) + { + var bucket = this.GetBucket( entry.HashCode ); + Debug.Assert( ( bucket >= 0 ) && ( bucket < m_buckets.Length ) ); + Debug.Assert( m_buckets[ bucket ] != ColumnHierarchyModel.None ); + + if( m_buckets[ bucket ] == index ) + { + m_buckets[ bucket ] = entry.Next; + } + else + { + // Repair the linked list. + var previous = m_buckets[ bucket ]; + var next = m_columns[ previous ].Next; + + while( next != index ) + { + Debug.Assert( next != ColumnHierarchyModel.None ); + previous = next; + next = m_columns[ next ].Next; + } + + Debug.Assert( next == index ); + + m_columns[ previous ] = m_columns[ previous ].SetNext( entry.Next ); + } + } + + m_columns[ index ] = new ColumnEntry( m_free ); + m_free = index; + + m_size--; + } + + private void Disconnect( int index ) + { + var relations = m_relations[ index ]; + + if( relations.Previous != ColumnHierarchyModel.None ) + { + this.SetRelations( relations.Previous, m_relations[ relations.Previous ].SetNext( relations.Next ) ); + } + else if( relations.Parent != ColumnHierarchyModel.None ) + { + Debug.Assert( m_relations[ relations.Parent ].FirstChild == index ); + + this.SetRelations( relations.Parent, m_relations[ relations.Parent ].SetFirstChild( relations.Next ) ); + } + + if( relations.Next != ColumnHierarchyModel.None ) + { + this.SetRelations( relations.Next, m_relations[ relations.Next ].SetPrevious( relations.Previous ) ); + } + } + + private void ConnectBefore( int index, int pivot ) + { + var sourceRelations = m_relations[ index ]; + var pivotRelations = m_relations[ pivot ]; + + if( pivotRelations.Previous != ColumnHierarchyModel.None ) + { + Debug.Assert( pivotRelations.Previous != index ); + + this.SetRelations( pivotRelations.Previous, m_relations[ pivotRelations.Previous ].SetNext( index ) ); + } + else if( pivotRelations.Parent != ColumnHierarchyModel.None ) + { + Debug.Assert( m_relations[ pivotRelations.Parent ].FirstChild == pivot ); + + this.SetRelations( pivotRelations.Parent, m_relations[ pivotRelations.Parent ].SetFirstChild( index ) ); + } + + this.SetRelations( index, new RelationEntry( pivotRelations.Parent, sourceRelations.FirstChild, pivotRelations.Previous, pivot ) ); + this.SetRelations( pivot, pivotRelations.SetPrevious( index ) ); + } + + private void ConnectAfter( int index, int pivot ) + { + var sourceRelations = m_relations[ index ]; + var pivotRelations = m_relations[ pivot ]; + + if( pivotRelations.Next != ColumnHierarchyModel.None ) + { + Debug.Assert( pivotRelations.Next != index ); + + this.SetRelations( pivotRelations.Next, m_relations[ pivotRelations.Next ].SetPrevious( index ) ); + } + + this.SetRelations( index, new RelationEntry( pivotRelations.Parent, sourceRelations.FirstChild, pivot, pivotRelations.Next ) ); + this.SetRelations( pivot, pivotRelations.SetNext( index ) ); + } + + private void ConnectUnder( int index, int pivot ) + { + var sourceRelations = m_relations[ index ]; + var pivotRelations = m_relations[ pivot ]; + + if( pivotRelations.FirstChild != ColumnHierarchyModel.None ) + { + Debug.Assert( pivotRelations.FirstChild != index ); + Debug.Assert( m_relations[ pivotRelations.FirstChild ].Previous == ColumnHierarchyModel.None ); + + this.SetRelations( pivotRelations.FirstChild, m_relations[ pivotRelations.FirstChild ].SetPrevious( index ) ); + } + + this.SetRelations( index, new RelationEntry( pivot, sourceRelations.FirstChild, ColumnHierarchyModel.None, pivotRelations.FirstChild ) ); + this.SetRelations( pivot, pivotRelations.SetFirstChild( index ) ); + } + + private void MoveBefore( int source, int pivot ) + { + if( m_preventLayoutChanged ) + throw new InvalidOperationException( "The layout cannot be updated." ); + + Debug.Assert( ( source >= 0 ) && ( source < m_capacity ) ); + Debug.Assert( ( pivot >= 0 ) && ( pivot < m_capacity ) ); + + // The entry is already at the proper location. + if( m_relations[ pivot ].Previous == source ) + return; + + if( source == pivot ) + throw new ArgumentException( "Cannot move the entry before itself.", "source" ); + + Debug.Assert( this.GetAncestorCount( source ) == this.GetAncestorCount( pivot ), "Cannot move entries on different level." ); + Debug.Assert( !this.IsStart( pivot ), "No entry can be moved before the start." ); + Debug.Assert( !this.IsStart( source ) && !this.IsEnd( source ) && !this.IsOrphan( source ), "The entry cannot be moved." ); + Debug.Assert( !this.IsSplitter( source ) || ( this.GetLevel( source ) == m_level - 1 ), "Only the topmost splitter can be moved." ); + Debug.Assert( !this.IsSplitter( pivot ) || ( this.GetLevel( pivot ) == m_level - 1 ), "An entry cannot be moved before the splitter on this level." ); + + this.Disconnect( source ); + this.ConnectBefore( source, pivot ); + } + + private void MoveAfter( int source, int pivot ) + { + if( m_preventLayoutChanged ) + throw new InvalidOperationException( "The layout cannot be updated." ); + + Debug.Assert( ( source >= 0 ) && ( source < m_capacity ) ); + Debug.Assert( ( pivot >= 0 ) && ( pivot < m_capacity ) ); + + // The entry is already at the proper location. + if( m_relations[ pivot ].Next == source ) + return; + + if( source == pivot ) + throw new ArgumentException( "Cannot move the entry after itself.", "source" ); + + Debug.Assert( this.GetAncestorCount( source ) == this.GetAncestorCount( pivot ), "Cannot move entries on different level." ); + Debug.Assert( !this.IsEnd( pivot ), "No entry can be moved after the end." ); + Debug.Assert( !this.IsOrphan( pivot ), "No entry can be moved after an orphan entry." ); + Debug.Assert( !this.IsStart( source ) && !this.IsEnd( source ) && !this.IsOrphan( source ), "The entry cannot be moved." ); + Debug.Assert( !this.IsSplitter( source ) || ( this.GetLevel( source ) == m_level - 1 ), "Only the topmost splitter can be move." ); + Debug.Assert( !this.IsSplitter( pivot ) || ( this.GetLevel( pivot ) == m_level - 1 ), "An entry cannot be moved after the splitter on this level." ); + + this.Disconnect( source ); + this.ConnectAfter( source, pivot ); + } + + private void MoveUnder( int source, int pivot ) + { + if( m_preventLayoutChanged ) + throw new InvalidOperationException( "The layout cannot be updated." ); + + Debug.Assert( ( source >= 0 ) && ( source < m_capacity ) ); + Debug.Assert( ( pivot >= 0 ) && ( pivot < m_capacity ) ); + + // The entry is already at the proper location. + if( m_relations[ source ].Parent == pivot ) + return; + + if( source == pivot ) + throw new ArgumentException( "Cannot move the entry under itself.", "source" ); + + Debug.Assert( this.GetAncestorCount( source ) == ( this.GetAncestorCount( pivot ) + 1 ), "The entry must be a location on the previous level." ); + Debug.Assert( !this.IsStart( source ) && !this.IsEnd( source ) && !this.IsOrphan( source ), "The entry cannot be moved." ); + Debug.Assert( !this.IsSplitter( source ), "A splitter cannot be moved under another entry." ); + Debug.Assert( !this.IsSplitter( pivot ), "An entry cannot be moved under a splitter." ); + + this.Disconnect( source ); + this.ConnectUnder( source, pivot ); + } + + private void SetRelations( int index, RelationEntry relations ) + { + Debug.Assert( ( index >= 0 ) && ( index < m_capacity ) ); + + var current = m_relations[ index ]; + var location = this.GetTargetLocation( index ); + Debug.Assert( location != null ); + + if( current.Parent != relations.Parent ) + { + this.OnLayoutChanging( new LayoutChangingEventArgs( location, LayoutChangingAction.ChangingParent ) ); + } + + if( current.FirstChild != relations.FirstChild ) + { + this.OnLayoutChanging( new LayoutChangingEventArgs( location, LayoutChangingAction.ChangingFirstChild ) ); + } + + if( current.Previous != relations.Previous ) + { + this.OnLayoutChanging( new LayoutChangingEventArgs( location, LayoutChangingAction.ChangingPrevious ) ); + } + + if( current.Next != relations.Next ) + { + this.OnLayoutChanging( new LayoutChangingEventArgs( location, LayoutChangingAction.ChangingNext ) ); + } + + m_relations[ index ] = relations; + + if( current.Parent != relations.Parent ) + { + this.OnLayoutChanged( new LayoutChangedEventArgs( location, LayoutChangedAction.ParentChanged ) ); + } + + if( current.FirstChild != relations.FirstChild ) + { + this.OnLayoutChanged( new LayoutChangedEventArgs( location, LayoutChangedAction.FirstChildChanged ) ); + } + + if( current.Previous != relations.Previous ) + { + this.OnLayoutChanged( new LayoutChangedEventArgs( location, LayoutChangedAction.PreviousChanged ) ); + } + + if( current.Next != relations.Next ) + { + this.OnLayoutChanged( new LayoutChangedEventArgs( location, LayoutChangedAction.NextChanged ) ); + } + } + + private TStatus GetStatus( int index ) + { + Debug.Assert( ( index >= 0 ) && ( index < m_capacity ) ); + + return m_status[ index ]; + } + + private void SetStatus( int index, TStatus value ) + { + Debug.Assert( ( index >= 0 ) && ( index < m_capacity ) ); + + var oldValue = m_status[ index ]; + if( object.Equals( oldValue, value ) ) + return; + + var columnLocation = this.GetTargetLocation( index ) as IColumnLocation; + Debug.Assert( columnLocation != null ); + + m_status[ index ] = value; + + this.OnStatusChanged( new StatusChangedEventArgs( columnLocation, oldValue, value ) ); + } + + private bool IsStart( int index ) + { + if( ( index < 0 ) || ( index >= m_capacity ) || this.IsColumn( index ) ) + return false; + + for( int level = m_level - 1; level >= 0; level-- ) + { + if( index == this.FindMark( level ).Start ) + return true; + } + + return false; + } + + private bool IsEnd( int index ) + { + if( ( index < 0 ) || ( index >= m_capacity ) || this.IsColumn( index ) ) + return false; + + for( int level = m_level - 1; level >= 0; level-- ) + { + if( index == this.FindMark( level ).End ) + return true; + } + + return false; + } + + private bool IsSplitter( int index ) + { + if( ( index < 0 ) || ( index >= m_capacity ) || this.IsColumn( index ) ) + return false; + + for( int level = m_level - 1; level >= 0; level-- ) + { + if( index == this.FindMark( level ).Splitter ) + return true; + } + + return false; + } + + private bool IsOrphan( int index ) + { + if( ( index < 0 ) || ( index >= m_capacity ) || this.IsColumn( index ) ) + return false; + + for( int level = m_level - 1; level >= 0; level-- ) + { + if( index == this.FindMark( level ).Orphan ) + return true; + } + + return false; + } + + private bool IsColumn( int index ) + { + if( ( index < 0 ) || ( index >= m_capacity ) ) + return false; + + return this.IsColumn( m_columns[ index ] ); + } + + private bool IsColumn( ColumnEntry entry ) + { + return !object.ReferenceEquals( entry.Column, null ); + } + + private MarkEntry FindMark( int level ) + { + Debug.Assert( ( level >= 0 ) && ( level < m_level ) ); + Debug.Assert( m_marks != null ); + Debug.Assert( level < m_marks.Length ); + + return m_marks[ level ]; + } + + private int FindColumn( TColumn column ) + { + Debug.Assert( !object.ReferenceEquals( column, null ) ); + + return this.FindColumn( column, column.GetHashCode() ); + } + + private int FindColumn( TColumn column, int hashCode ) + { + Debug.Assert( !object.ReferenceEquals( column, null ) ); + Debug.Assert( m_buckets != null ); + Debug.Assert( m_columns != null ); + + var bucket = this.GetBucket( hashCode ); + Debug.Assert( ( bucket >= 0 ) && ( bucket < m_buckets.Length ) ); + + var index = m_buckets[ bucket ]; + + while( index != ColumnHierarchyModel.None ) + { + var entry = m_columns[ index ]; + if( ( entry.HashCode == hashCode ) && object.Equals( entry.Column, column ) ) + return index; + + index = entry.Next; + } + + return ColumnHierarchyModel.None; + } + + private StartLocation CreateStartLocation( int level, int index ) + { + Debug.Assert( this.IsStart( index ) ); + + return new StartLocation( this, level, index ); + } + + private EndLocation CreateEndLocation( int level, int index ) + { + Debug.Assert( this.IsEnd( index ) ); + + return new EndLocation( this, level, index ); + } + + private SplitterLocation CreateSplitterLocation( int level, int index ) + { + Debug.Assert( this.IsSplitter( index ) ); + + return new SplitterLocation( this, level, index ); + } + + private OrphanLocation CreateOrphanLocation( int level, int index ) + { + Debug.Assert( this.IsOrphan( index ) ); + + return new OrphanLocation( this, level, index ); + } + + private ColumnLocation CreateColumnLocation( int index ) + { + Debug.Assert( this.IsColumn( index ) ); + + var entry = m_columns[ index ]; + + return new ColumnLocation( this, entry.Column, entry.HashCode, index ); + } + + private int GetParent( int index ) + { + Debug.Assert( ( index >= 0 ) && ( index < m_capacity ) ); + Debug.Assert( m_relations != null ); + + return m_relations[ index ].Parent; + } + + private int GetFirstChild( int index ) + { + Debug.Assert( ( index >= 0 ) && ( index < m_capacity ) ); + Debug.Assert( m_relations != null ); + + return m_relations[ index ].FirstChild; + } + + private int GetPreviousSibling( int index ) + { + Debug.Assert( ( index >= 0 ) && ( index < m_capacity ) ); + Debug.Assert( m_relations != null ); + + return m_relations[ index ].Previous; + } + + private int GetNextSibling( int index ) + { + Debug.Assert( ( index >= 0 ) && ( index < m_capacity ) ); + Debug.Assert( m_relations != null ); + + return m_relations[ index ].Next; + } + + private int GetPreviousSiblingOrCousin( int index ) + { + Debug.Assert( ( index >= 0 ) && ( index < m_capacity ) ); + + var relations = m_relations[ index ]; + var target = relations.Previous; + + if( target != ColumnHierarchyModel.None ) + return target; + + var parent = relations.Parent; + if( parent != ColumnHierarchyModel.None ) + { + var oncle = parent; + + while( true ) + { + oncle = this.GetPreviousSiblingOrCousin( oncle ); + if( oncle == ColumnHierarchyModel.None ) + break; + + target = this.GetFirstChild( oncle ); + if( target != ColumnHierarchyModel.None ) + { + while( this.GetNextSibling( target ) != ColumnHierarchyModel.None ) + { + target = this.GetNextSibling( target ); + } + + return target; + } + } + } + + // No more sibling. + return ColumnHierarchyModel.None; + } + + private int GetNextSiblingOrCousin( int index ) + { + Debug.Assert( ( index >= 0 ) && ( index < m_capacity ) ); + + var relations = m_relations[ index ]; + var target = relations.Next; + + if( target != ColumnHierarchyModel.None ) + return target; + + var parent = relations.Parent; + if( parent != ColumnHierarchyModel.None ) + { + var oncle = parent; + + while( true ) + { + oncle = this.GetNextSiblingOrCousin( oncle ); + if( oncle == ColumnHierarchyModel.None ) + break; + + target = this.GetFirstChild( oncle ); + if( target != ColumnHierarchyModel.None ) + return target; + } + } + + // No more sibling. + return ColumnHierarchyModel.None; + } + + private ILocation GetTargetLocation( int index ) + { + if( index == ColumnHierarchyModel.None ) + return null; + + if( this.IsColumn( index ) ) + return this.CreateColumnLocation( index ); + + for( int level = m_level - 1; level >= 0; level-- ) + { + var entry = this.FindMark( level ); + if( entry.Start == index ) + return this.CreateStartLocation( level, index ); + + if( entry.End == index ) + return this.CreateEndLocation( level, index ); + + if( entry.Splitter == index ) + return this.CreateSplitterLocation( level, index ); + + if( entry.Orphan == index ) + return this.CreateOrphanLocation( level, index ); + } + + throw new InvalidOperationException(); + } + + private int GetLevel( int index ) + { + Debug.Assert( m_level > 0 ); + + var ancestors = this.GetAncestorCount( index ); + Debug.Assert( ancestors < m_level ); + + return m_level - ancestors - 1; + } + + private int GetAncestorCount( int index ) + { + Debug.Assert( ( index >= 0 ) && ( index < m_capacity ) ); + + var count = -1; + + while( index != ColumnHierarchyModel.None ) + { + index = this.GetParent( index ); + count++; + } + + Debug.Assert( count >= 0 ); + + return count; + } + + private int GetBucket( int hashCode ) + { + return ColumnHierarchyModel.GetBucket( hashCode, m_capacity ); + } + + private void EnsureMarks( int level, MarkEntry entry ) + { + if( ( m_marks == null ) || ( level < 0 ) || ( level >= m_marks.Length ) || !object.Equals( entry, m_marks[ level ] ) ) + throw new InvalidOperationException( "The markers are no longer valid." ); + } + + private int EnsureStart( int level, int index ) + { + if( ( m_marks == null ) || ( level < 0 ) || ( level >= m_marks.Length ) || ( index != m_marks[ level ].Start ) ) + throw new InvalidOperationException( "The location is no longer valid." ); + + return level; + } + + private int EnsureEnd( int level, int index ) + { + if( ( m_marks == null ) || ( level < 0 ) || ( level >= m_marks.Length ) || ( index != m_marks[ level ].End ) ) + throw new InvalidOperationException( "The location is no longer valid." ); + + return level; + } + + private int EnsureSplitter( int level, int index ) + { + if( ( m_marks == null ) || ( level < 0 ) || ( level >= m_marks.Length ) || ( index != m_marks[ level ].Splitter ) ) + throw new InvalidOperationException( "The location is no longer valid." ); + + return level; + } + + private int EnsureOrphan( int level, int index ) + { + if( ( m_marks == null ) || ( level < 0 ) || ( level >= m_marks.Length ) || ( index != m_marks[ level ].Orphan ) ) + throw new InvalidOperationException( "The location is no longer valid." ); + + return level; + } + + private int EnsureColumn( TColumn column, int hashCode, int index ) + { + if( ( index < 0 ) || ( index >= m_capacity ) ) + throw new InvalidOperationException( "The column location is no longer valid." ); + + var entry = m_columns[ index ]; + if( ( hashCode != entry.HashCode ) || !object.Equals( column, entry.Column ) ) + throw new InvalidOperationException( "The column location is no longer valid." ); + + return this.GetLevel( index ); + } + + private void EnsureCapacity() + { + // Make sure the collection is not full. + if( m_size != m_capacity ) + return; + + Debug.Assert( m_free == ColumnHierarchyModel.None ); + this.EnsureCapacity( m_capacity * 2L ); + Debug.Assert( m_free != ColumnHierarchyModel.None ); + Debug.Assert( m_size != m_capacity ); + } + + private void EnsureCapacity( long min ) + { + if( ( m_capacity >= min ) && ( m_capacity > 0 ) ) + return; + + var capacity = ColumnHierarchyModel.FindNextSize( min ); + Debug.Assert( capacity > 0 ); + + m_buckets = new int[ capacity ]; + + Array.Resize( ref m_columns, capacity ); + Array.Resize( ref m_status, capacity ); + Array.Resize( ref m_relations, capacity ); + + for( int i = 0; i < m_buckets.Length; i++ ) + { + m_buckets[ i ] = ColumnHierarchyModel.None; + } + + for( int i = m_capacity; i < capacity; i++ ) + { + m_columns[ i ] = new ColumnEntry( ( i < capacity - 1 ) ? i + 1 : ColumnHierarchyModel.None ); + m_status[ i ] = default( TStatus ); + m_relations[ i ] = RelationEntry.Default; + } + + // Rehash the elements to initialize the buckets. + for( int i = 0; i < m_capacity; i++ ) + { + var entry = m_columns[ i ]; + + // Only column entry needs to adjust the buckets. + if( this.IsColumn( entry ) ) + { + var bucket = ColumnHierarchyModel.GetBucket( entry.HashCode, capacity ); + Debug.Assert( ( bucket >= 0 ) && ( bucket < capacity ) ); + + var index = m_buckets[ bucket ]; + + m_buckets[ bucket ] = i; + m_columns[ i ] = entry.SetNext( index ); + } + } + + m_free = m_capacity; + m_capacity = capacity; + } + + private static int FindNextSize( long min ) + { + var sizes = ArrayHelper.Sizes; + + for( int i = 0; i < sizes.Length; i++ ) + { + var size = sizes[ i ]; + + if( size >= min ) + return size; + } + + throw new InvalidOperationException( "Cannot find a larger size." ); + } + + private static int GetBucket( int hashCode, int capacity ) + { + Debug.Assert( capacity > 0 ); + + // Remove the negative sign without using Math.Abs to handle the case of int.MinValue. + return ( hashCode & 0x7fffffff ) % capacity; + } + + private int[] m_buckets; + private ColumnEntry[] m_columns; + private TStatus[] m_status; + private RelationEntry[] m_relations; + private MarkEntry[] m_marks; + private int m_level; //0 + private int m_capacity; //0 + private int m_size; //0 + private bool m_preventLayoutChanged; //false + private int m_free = ColumnHierarchyModel.None; + + #region IMarkers Internal Interface + + internal interface IMarkers + { + ILocation Start + { + get; + } + + ILocation End + { + get; + } + + ILocation Splitter + { + get; + } + + ILocation Orphan + { + get; + } + } + + #endregion + + #region ILocation Internal Interface + + internal interface ILocation + { + LocationType Type + { + get; + } + + int Level + { + get; + } + + ILocation GetParent(); + ILocation GetFirstChild(); + + ILocation GetPreviousSibling(); + ILocation GetNextSibling(); + + ILocation GetPreviousSiblingOrCousin(); + ILocation GetNextSiblingOrCousin(); + + bool CanMoveBefore( ILocation location ); + bool CanMoveAfter( ILocation location ); + bool CanMoveUnder( ILocation location ); + + void MoveBefore( ILocation location ); + void MoveAfter( ILocation location ); + void MoveUnder( ILocation location ); + } + + #endregion + + #region IColumnLocation Internal Interface + + internal interface IColumnLocation : ILocation + { + TColumn Column + { + get; + } + + TStatus Status + { + get; + set; + } + } + + #endregion + + #region LayoutChangingEventArgs Internal Class + + internal sealed class LayoutChangingEventArgs : EventArgs + { + internal LayoutChangingEventArgs( ILocation location, LayoutChangingAction action ) + { + m_location = location; + m_action = action; + } + + internal ILocation Location + { + get + { + return m_location; + } + } + + internal LayoutChangingAction Action + { + get + { + return m_action; + } + } + + private readonly ILocation m_location; + private readonly LayoutChangingAction m_action; + } + + #endregion + + #region LayoutChangedEventArgs Internal Class + + internal sealed class LayoutChangedEventArgs : EventArgs + { + internal LayoutChangedEventArgs( ILocation location, LayoutChangedAction action ) + { + m_location = location; + m_action = action; + } + + internal ILocation Location + { + get + { + return m_location; + } + } + + internal LayoutChangedAction Action + { + get + { + return m_action; + } + } + + private readonly ILocation m_location; + private readonly LayoutChangedAction m_action; + } + + #endregion + + #region StatusChangedEventArgs Internal Class + + internal sealed class StatusChangedEventArgs : EventArgs + { + internal StatusChangedEventArgs( IColumnLocation location, TStatus oldValue, TStatus newValue ) + { + m_location = location; + m_oldValue = oldValue; + m_newValue = newValue; + } + + internal IColumnLocation Location + { + get + { + return m_location; + } + } + + internal TStatus OldValue + { + get + { + return m_oldValue; + } + } + + internal TStatus NewValue + { + get + { + return m_newValue; + } + } + + private readonly IColumnLocation m_location; + private readonly TStatus m_oldValue; + private readonly TStatus m_newValue; + } + + #endregion + + #region LayoutChangingAction Internal Enum + + internal enum LayoutChangingAction + { + Clearing, + Removing, + ChangingParent, + ChangingFirstChild, + ChangingPrevious, + ChangingNext, + } + + #endregion + + #region LayoutChangedAction Internal Enum + + internal enum LayoutChangedAction + { + Cleared, + Added, + ParentChanged, + FirstChildChanged, + PreviousChanged, + NextChanged, + } + + #endregion + + #region IPivotLocation Private Interface + + private interface IPivotLocation + { + bool CanBeNextSiblingOf( IMovableLocation location ); + bool CanBePreviousSiblingOf( IMovableLocation location ); + bool CanBeParentOf( IMovableLocation location ); + + void SetHasNextSiblingOf( IMovableLocation location ); + void SetHasPreviousSiblingOf( IMovableLocation location ); + void SetHasParentOf( IMovableLocation location ); + } + + #endregion + + #region IMovableLocation Private Interface + + private interface IMovableLocation + { + bool CanMoveBefore( StartLocation location ); + bool CanMoveBefore( EndLocation location ); + bool CanMoveBefore( SplitterLocation location ); + bool CanMoveBefore( OrphanLocation location ); + bool CanMoveBefore( ColumnLocation location ); + + bool CanMoveAfter( StartLocation location ); + bool CanMoveAfter( EndLocation location ); + bool CanMoveAfter( SplitterLocation location ); + bool CanMoveAfter( OrphanLocation location ); + bool CanMoveAfter( ColumnLocation location ); + + bool CanMoveUnder( StartLocation location ); + bool CanMoveUnder( EndLocation location ); + bool CanMoveUnder( SplitterLocation location ); + bool CanMoveUnder( OrphanLocation location ); + bool CanMoveUnder( ColumnLocation location ); + + void MoveBefore( StartLocation location ); + void MoveBefore( EndLocation location ); + void MoveBefore( SplitterLocation location ); + void MoveBefore( OrphanLocation location ); + void MoveBefore( ColumnLocation location ); + + void MoveAfter( StartLocation location ); + void MoveAfter( EndLocation location ); + void MoveAfter( SplitterLocation location ); + void MoveAfter( OrphanLocation location ); + void MoveAfter( ColumnLocation location ); + + void MoveUnder( StartLocation location ); + void MoveUnder( EndLocation location ); + void MoveUnder( SplitterLocation location ); + void MoveUnder( OrphanLocation location ); + void MoveUnder( ColumnLocation location ); + } + + #endregion + + #region Markers Private Class + + private sealed class Markers : IMarkers + { + internal Markers( ColumnHierarchyModel owner, int level, MarkEntry entry ) + { + Debug.Assert( owner != null ); + + m_owner = owner; + m_level = level; + m_entry = entry; + } + + public ILocation Start + { + get + { + this.EnsureMarks(); + + return m_owner.CreateStartLocation( m_level, m_entry.Start ); + } + } + + public ILocation End + { + get + { + this.EnsureMarks(); + + return m_owner.CreateEndLocation( m_level, m_entry.End ); + } + } + + public ILocation Splitter + { + get + { + this.EnsureMarks(); + + return m_owner.CreateSplitterLocation( m_level, m_entry.Splitter ); + } + } + + public ILocation Orphan + { + get + { + this.EnsureMarks(); + + return m_owner.CreateOrphanLocation( m_level, m_entry.Orphan ); + } + } + + public override int GetHashCode() + { + return m_level; + } + + public override bool Equals( object obj ) + { + var target = obj as Markers; + if( target == null ) + return false; + + return ( m_level == target.m_level ) + && ( object.Equals( m_entry, target.m_entry ) ) + && ( m_owner == target.m_owner ); + } + + private void EnsureMarks() + { + m_owner.EnsureMarks( m_level, m_entry ); + } + + private readonly ColumnHierarchyModel m_owner; + private readonly int m_level; + private readonly MarkEntry m_entry; + } + + #endregion + + #region Location Private Class + + private abstract class Location : ILocation, IMovableLocation, IPivotLocation + { + protected Location( ColumnHierarchyModel owner, int index ) + { + Debug.Assert( owner != null ); + + m_owner = owner; + m_index = index; + } + + protected abstract LocationType Type + { + get; + } + + protected int Level + { + get + { + return this.EnsureLocation(); + } + } + + internal int Index + { + get + { + return m_index; + } + } + + internal ColumnHierarchyModel Owner + { + get + { + return m_owner; + } + } + + LocationType ILocation.Type + { + get + { + return this.Type; + } + } + + int ILocation.Level + { + get + { + return this.Level; + } + } + + public override int GetHashCode() + { + return m_index; + } + + public override bool Equals( object obj ) + { + var target = obj as Location; + if( target == null ) + return false; + + return ( m_index == target.m_index ) + && ( m_owner == target.m_owner ); + } + + protected TStatus GetStatus() + { + this.EnsureLocation(); + + return m_owner.GetStatus( m_index ); + } + + protected void SetStatus( TStatus status ) + { + this.EnsureLocation(); + + m_owner.SetStatus( m_index, status ); + } + + protected void MoveBeforeCore( Location location ) + { + m_owner.MoveBefore( m_index, location.m_index ); + } + + protected void MoveAfterCore( Location location ) + { + m_owner.MoveAfter( m_index, location.m_index ); + } + + protected void MoveUnderCore( Location location ) + { + m_owner.MoveUnder( m_index, location.m_index ); + } + + protected virtual bool CanMoveBefore( StartLocation location ) + { + return false; + } + + protected virtual bool CanMoveBefore( EndLocation location ) + { + return false; + } + + protected virtual bool CanMoveBefore( SplitterLocation location ) + { + return false; + } + + protected virtual bool CanMoveBefore( OrphanLocation location ) + { + return false; + } + + protected virtual bool CanMoveBefore( ColumnLocation location ) + { + return false; + } + + protected virtual bool CanMoveAfter( StartLocation location ) + { + return false; + } + + protected virtual bool CanMoveAfter( EndLocation location ) + { + return false; + } + + protected virtual bool CanMoveAfter( SplitterLocation location ) + { + return false; + } + + protected virtual bool CanMoveAfter( OrphanLocation location ) + { + return false; + } + + protected virtual bool CanMoveAfter( ColumnLocation location ) + { + return false; + } + + protected virtual bool CanMoveUnder( StartLocation location ) + { + return false; + } + + protected virtual bool CanMoveUnder( EndLocation location ) + { + return false; + } + + protected virtual bool CanMoveUnder( SplitterLocation location ) + { + return false; + } + + protected virtual bool CanMoveUnder( OrphanLocation location ) + { + return false; + } + + protected virtual bool CanMoveUnder( ColumnLocation location ) + { + return false; + } + + protected virtual void MoveBefore( StartLocation location ) + { + throw new NotSupportedException(); + } + + protected virtual void MoveBefore( EndLocation location ) + { + throw new NotSupportedException(); + } + + protected virtual void MoveBefore( SplitterLocation location ) + { + throw new NotSupportedException(); + } + + protected virtual void MoveBefore( OrphanLocation location ) + { + throw new NotSupportedException(); + } + + protected virtual void MoveBefore( ColumnLocation location ) + { + throw new NotSupportedException(); + } + + protected virtual void MoveAfter( StartLocation location ) + { + throw new NotSupportedException(); + } + + protected virtual void MoveAfter( EndLocation location ) + { + throw new NotSupportedException(); + } + + protected virtual void MoveAfter( SplitterLocation location ) + { + throw new NotSupportedException(); + } + + protected virtual void MoveAfter( OrphanLocation location ) + { + throw new NotSupportedException(); + } + + protected virtual void MoveAfter( ColumnLocation location ) + { + throw new NotSupportedException(); + } + + protected virtual void MoveUnder( StartLocation location ) + { + throw new NotSupportedException(); + } + + protected virtual void MoveUnder( EndLocation location ) + { + throw new NotSupportedException(); + } + + protected virtual void MoveUnder( SplitterLocation location ) + { + throw new NotSupportedException(); + } + + protected virtual void MoveUnder( OrphanLocation location ) + { + throw new NotSupportedException(); + } + + protected virtual void MoveUnder( ColumnLocation location ) + { + throw new NotSupportedException(); + } + + protected abstract bool CanBeNextSiblingOf( IMovableLocation location ); + protected abstract bool CanBePreviousSiblingOf( IMovableLocation location ); + protected abstract bool CanBeParentOf( IMovableLocation location ); + protected abstract void SetHasNextSiblingOf( IMovableLocation location ); + protected abstract void SetHasPreviousSiblingOf( IMovableLocation location ); + protected abstract void SetHasParentOf( IMovableLocation location ); + + internal abstract int EnsureLocation(); + + private int EnsureLocation( ILocation location ) + { + if( location == null ) + throw new ArgumentNullException( "location" ); + + var target = location as Location; + if( target == null ) + throw new ArgumentException( "The location must derive from Location.", "location" ); + + if( target.Owner != m_owner ) + throw new ArgumentException( "The location must share the same owner.", "location" ); + + return target.EnsureLocation(); + } + + private void EnsureSiblingLocation( ILocation location ) + { + var sourceLevel = this.EnsureLocation(); + var targetLevel = this.EnsureLocation( location ); + + if( sourceLevel != targetLevel ) + throw new ArgumentException( "The location must be on the same level.", "location" ); + } + + private void EnsureParentLocation( ILocation location ) + { + var sourceLevel = this.EnsureLocation(); + var targetLevel = this.EnsureLocation( location ); + + if( sourceLevel != targetLevel - 1 ) + throw new ArgumentException( "The location must be on the parent level.", "location" ); + } + + ILocation ILocation.GetParent() + { + this.EnsureLocation(); + return m_owner.GetTargetLocation( m_owner.GetParent( m_index ) ); + } + + ILocation ILocation.GetFirstChild() + { + this.EnsureLocation(); + return m_owner.GetTargetLocation( m_owner.GetFirstChild( m_index ) ); + } + + ILocation ILocation.GetPreviousSibling() + { + this.EnsureLocation(); + return m_owner.GetTargetLocation( m_owner.GetPreviousSibling( m_index ) ); + } + + ILocation ILocation.GetNextSibling() + { + this.EnsureLocation(); + return m_owner.GetTargetLocation( m_owner.GetNextSibling( m_index ) ); + } + + ILocation ILocation.GetPreviousSiblingOrCousin() + { + this.EnsureLocation(); + return m_owner.GetTargetLocation( m_owner.GetPreviousSiblingOrCousin( m_index ) ); + } + + ILocation ILocation.GetNextSiblingOrCousin() + { + this.EnsureLocation(); + return m_owner.GetTargetLocation( m_owner.GetNextSiblingOrCousin( m_index ) ); + } + + bool ILocation.CanMoveBefore( ILocation location ) + { + if( location == null ) + return false; + + if( object.Equals( location, this ) ) + return false; + + var currentLevel = this.EnsureLocation(); + var targetLevel = this.EnsureLocation( location ); + + if( currentLevel != targetLevel ) + return false; + + Debug.Assert( location is IPivotLocation ); + + return ( ( IPivotLocation )location ).CanBeNextSiblingOf( this ); + } + + bool ILocation.CanMoveAfter( ILocation location ) + { + if( location == null ) + return false; + + if( object.Equals( location, this ) ) + return false; + + var currentLevel = this.EnsureLocation(); + var targetLevel = this.EnsureLocation( location ); + + if( currentLevel != targetLevel ) + return false; + + Debug.Assert( location is IPivotLocation ); + + return ( ( IPivotLocation )location ).CanBePreviousSiblingOf( this ); + } + + bool ILocation.CanMoveUnder( ILocation location ) + { + if( location == null ) + return false; + + if( object.Equals( location, this ) ) + return false; + + var currentLevel = this.EnsureLocation(); + var targetLevel = this.EnsureLocation( location ); + + if( currentLevel != targetLevel - 1 ) + return false; + + Debug.Assert( location is IPivotLocation ); + + return ( ( IPivotLocation )location ).CanBeParentOf( this ); + } + + void ILocation.MoveBefore( ILocation location ) + { + this.EnsureSiblingLocation( location ); + + Debug.Assert( ( ( ILocation )this ).CanMoveBefore( location ) ); + Debug.Assert( location is IPivotLocation ); + + ( ( IPivotLocation )location ).SetHasNextSiblingOf( this ); + } + + void ILocation.MoveAfter( ILocation location ) + { + this.EnsureSiblingLocation( location ); + + Debug.Assert( ( ( ILocation )this ).CanMoveAfter( location ) ); + Debug.Assert( location is IPivotLocation ); + + ( ( IPivotLocation )location ).SetHasPreviousSiblingOf( this ); + } + + void ILocation.MoveUnder( ILocation location ) + { + this.EnsureParentLocation( location ); + + Debug.Assert( ( ( ILocation )this ).CanMoveUnder( location ) ); + Debug.Assert( location is IPivotLocation ); + + ( ( IPivotLocation )location ).SetHasParentOf( this ); + } + + bool IMovableLocation.CanMoveBefore( StartLocation location ) + { + return this.CanMoveBefore( location ); + } + + bool IMovableLocation.CanMoveBefore( EndLocation location ) + { + return this.CanMoveBefore( location ); + } + + bool IMovableLocation.CanMoveBefore( SplitterLocation location ) + { + return this.CanMoveBefore( location ); + } + + bool IMovableLocation.CanMoveBefore( OrphanLocation location ) + { + return this.CanMoveBefore( location ); + } + + bool IMovableLocation.CanMoveBefore( ColumnLocation location ) + { + return this.CanMoveBefore( location ); + } + + bool IMovableLocation.CanMoveAfter( StartLocation location ) + { + return this.CanMoveAfter( location ); + } + + bool IMovableLocation.CanMoveAfter( EndLocation location ) + { + return this.CanMoveAfter( location ); + } + + bool IMovableLocation.CanMoveAfter( SplitterLocation location ) + { + return this.CanMoveAfter( location ); + } + + bool IMovableLocation.CanMoveAfter( OrphanLocation location ) + { + return this.CanMoveAfter( location ); + } + + bool IMovableLocation.CanMoveAfter( ColumnLocation location ) + { + return this.CanMoveAfter( location ); + } + + bool IMovableLocation.CanMoveUnder( StartLocation location ) + { + return this.CanMoveUnder( location ); + } + + bool IMovableLocation.CanMoveUnder( EndLocation location ) + { + return this.CanMoveUnder( location ); + } + + bool IMovableLocation.CanMoveUnder( SplitterLocation location ) + { + return this.CanMoveUnder( location ); + } + + bool IMovableLocation.CanMoveUnder( OrphanLocation location ) + { + return this.CanMoveUnder( location ); + } + + bool IMovableLocation.CanMoveUnder( ColumnLocation location ) + { + return this.CanMoveUnder( location ); + } + + void IMovableLocation.MoveBefore( StartLocation location ) + { + this.MoveBefore( location ); + } + + void IMovableLocation.MoveBefore( EndLocation location ) + { + this.MoveBefore( location ); + } + + void IMovableLocation.MoveBefore( SplitterLocation location ) + { + this.MoveBefore( location ); + } + + void IMovableLocation.MoveBefore( OrphanLocation location ) + { + this.MoveBefore( location ); + } + + void IMovableLocation.MoveBefore( ColumnLocation location ) + { + this.MoveBefore( location ); + } + + void IMovableLocation.MoveAfter( StartLocation location ) + { + this.MoveAfter( location ); + } + + void IMovableLocation.MoveAfter( EndLocation location ) + { + this.MoveAfter( location ); + } + + void IMovableLocation.MoveAfter( SplitterLocation location ) + { + this.MoveAfter( location ); + } + + void IMovableLocation.MoveAfter( OrphanLocation location ) + { + this.MoveAfter( location ); + } + + void IMovableLocation.MoveAfter( ColumnLocation location ) + { + this.MoveAfter( location ); + } + + void IMovableLocation.MoveUnder( StartLocation location ) + { + this.MoveUnder( location ); + } + + void IMovableLocation.MoveUnder( EndLocation location ) + { + this.MoveUnder( location ); + } + + void IMovableLocation.MoveUnder( SplitterLocation location ) + { + this.MoveUnder( location ); + } + + void IMovableLocation.MoveUnder( OrphanLocation location ) + { + this.MoveUnder( location ); + } + + void IMovableLocation.MoveUnder( ColumnLocation location ) + { + this.MoveUnder( location ); + } + + bool IPivotLocation.CanBeNextSiblingOf( IMovableLocation location ) + { + return this.CanBeNextSiblingOf( location ); + } + + bool IPivotLocation.CanBePreviousSiblingOf( IMovableLocation location ) + { + return this.CanBePreviousSiblingOf( location ); + } + + bool IPivotLocation.CanBeParentOf( IMovableLocation location ) + { + return this.CanBeParentOf( location ); + } + + void IPivotLocation.SetHasNextSiblingOf( IMovableLocation location ) + { + this.SetHasNextSiblingOf( location ); + } + + void IPivotLocation.SetHasPreviousSiblingOf( IMovableLocation location ) + { + this.SetHasPreviousSiblingOf( location ); + } + + void IPivotLocation.SetHasParentOf( IMovableLocation location ) + { + this.SetHasParentOf( location ); + } + + private readonly ColumnHierarchyModel m_owner; + private readonly int m_index; + } + + #endregion + + #region StartLocation Private Class + + private sealed class StartLocation : Location + { + internal StartLocation( ColumnHierarchyModel owner, int level, int index ) + : base( owner, index ) + { + m_level = level; + } + + protected override LocationType Type + { + get + { + return LocationType.Start; + } + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public override bool Equals( object obj ) + { + var target = obj as StartLocation; + if( target == null ) + return false; + + return ( m_level == target.m_level ) + && ( base.Equals( target ) ); + } + + protected override bool CanBeNextSiblingOf( IMovableLocation location ) + { + return location.CanMoveBefore( this ); + } + + protected override bool CanBePreviousSiblingOf( IMovableLocation location ) + { + return location.CanMoveAfter( this ); + } + + protected override bool CanBeParentOf( IMovableLocation location ) + { + return location.CanMoveUnder( this ); + } + + protected override void SetHasNextSiblingOf( IMovableLocation location ) + { + location.MoveBefore( this ); + } + + protected override void SetHasPreviousSiblingOf( IMovableLocation location ) + { + location.MoveAfter( this ); + } + + protected override void SetHasParentOf( IMovableLocation location ) + { + location.MoveUnder( this ); + } + + internal override int EnsureLocation() + { + return this.Owner.EnsureStart( m_level, this.Index ); + } + + private readonly int m_level; + } + + #endregion + + #region EndLocation Private Class + + private sealed class EndLocation : Location + { + internal EndLocation( ColumnHierarchyModel owner, int level, int index ) + : base( owner, index ) + { + m_level = level; + } + + protected override LocationType Type + { + get + { + return LocationType.End; + } + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public override bool Equals( object obj ) + { + var target = obj as EndLocation; + if( target == null ) + return false; + + return ( m_level == target.m_level ) + && ( base.Equals( target ) ); + } + + protected override bool CanBeNextSiblingOf( IMovableLocation location ) + { + return location.CanMoveBefore( this ); + } + + protected override bool CanBePreviousSiblingOf( IMovableLocation location ) + { + return location.CanMoveAfter( this ); + } + + protected override bool CanBeParentOf( IMovableLocation location ) + { + return location.CanMoveUnder( this ); + } + + protected override void SetHasNextSiblingOf( IMovableLocation location ) + { + location.MoveBefore( this ); + } + + protected override void SetHasPreviousSiblingOf( IMovableLocation location ) + { + location.MoveAfter( this ); + } + + protected override void SetHasParentOf( IMovableLocation location ) + { + location.MoveUnder( this ); + } + + internal override int EnsureLocation() + { + return this.Owner.EnsureEnd( m_level, this.Index ); + } + + private readonly int m_level; + } + + #endregion + + #region SplitterLocation Private Class + + private sealed class SplitterLocation : Location + { + internal SplitterLocation( ColumnHierarchyModel owner, int level, int index ) + : base( owner, index ) + { + m_level = level; + } + + protected override LocationType Type + { + get + { + return LocationType.Splitter; + } + } + + internal bool IsMovable + { + get + { + return ( m_level == this.Owner.LevelCount - 1 ); + } + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public override bool Equals( object obj ) + { + var target = obj as SplitterLocation; + if( target == null ) + return false; + + return ( m_level == target.m_level ) + && ( base.Equals( target ) ); + } + + protected override bool CanMoveBefore( ColumnLocation location ) + { + return this.CanMoveSplitterBefore( location ); + } + + protected override bool CanMoveBefore( OrphanLocation location ) + { + return this.CanMoveSplitterBefore( location ); + } + + protected override bool CanMoveAfter( ColumnLocation location ) + { + return this.CanMoveSplitterAfter( location ); + } + + protected override bool CanMoveAfter( StartLocation location ) + { + return this.CanMoveSplitterAfter( location ); + } + + protected override void MoveBefore( ColumnLocation location ) + { + this.MoveSplitterBefore( location ); + } + + protected override void MoveBefore( OrphanLocation location ) + { + this.MoveSplitterBefore( location ); + } + + protected override void MoveAfter( ColumnLocation location ) + { + this.MoveSplitterAfter( location ); + } + + protected override void MoveAfter( StartLocation location ) + { + this.MoveSplitterAfter( location ); + } + + protected override bool CanBeNextSiblingOf( IMovableLocation location ) + { + return location.CanMoveBefore( this ); + } + + protected override bool CanBePreviousSiblingOf( IMovableLocation location ) + { + return location.CanMoveAfter( this ); + } + + protected override bool CanBeParentOf( IMovableLocation location ) + { + return location.CanMoveUnder( this ); + } + + protected override void SetHasNextSiblingOf( IMovableLocation location ) + { + location.MoveBefore( this ); + } + + protected override void SetHasPreviousSiblingOf( IMovableLocation location ) + { + location.MoveAfter( this ); + } + + protected override void SetHasParentOf( IMovableLocation location ) + { + location.MoveUnder( this ); + } + + internal override int EnsureLocation() + { + return this.Owner.EnsureSplitter( m_level, this.Index ); + } + + private bool CanMoveSplitterBefore( ILocation location ) + { + if( this.IsMovable ) + return true; + + // The current and target locations should not be on the top-most level. + Debug.Assert( m_level < this.Owner.LevelCount - 1 ); + + // The splitter may not move or a merged column is going to be splitted. + if( location.GetPreviousSibling() != null ) + return false; + + var parentLocation = ( ( ILocation )this ).GetParent(); + Debug.Assert( parentLocation != null ); + + return parentLocation.CanMoveBefore( location.GetParent() ); + } + + private bool CanMoveSplitterAfter( ILocation location ) + { + if( this.IsMovable ) + return true; + + // The current and target locations should not be on the top-most level. + Debug.Assert( m_level < this.Owner.LevelCount - 1 ); + + // The splitter may not move or a merged column is going to be splitted. + if( location.GetNextSibling() != null ) + return false; + + var parentLocation = ( ( ILocation )this ).GetParent(); + Debug.Assert( parentLocation != null ); + + return parentLocation.CanMoveAfter( location.GetParent() ); + } + + private void MoveSplitterBefore( Location location ) + { + if( this.IsMovable ) + { + this.MoveBeforeCore( location ); + } + else + { + var parentLocation = ( ( ILocation )this ).GetParent(); + Debug.Assert( parentLocation != null ); + + parentLocation.MoveBefore( ( ( ILocation )location ).GetParent() ); + } + } + + private void MoveSplitterAfter( Location location ) + { + if( this.IsMovable ) + { + this.MoveAfterCore( location ); + } + else + { + var parentLocation = ( ( ILocation )this ).GetParent(); + Debug.Assert( parentLocation != null ); + + parentLocation.MoveAfter( ( ( ILocation )location ).GetParent() ); + } + } + + private readonly int m_level; + } + + #endregion + + #region OrphanLocation Private Class + + private sealed class OrphanLocation : Location + { + internal OrphanLocation( ColumnHierarchyModel owner, int level, int index ) + : base( owner, index ) + { + m_level = level; + } + + protected override LocationType Type + { + get + { + return LocationType.Orphan; + } + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public override bool Equals( object obj ) + { + var target = obj as OrphanLocation; + if( target == null ) + return false; + + return ( m_level == target.m_level ) + && ( base.Equals( target ) ); + } + + protected override bool CanBeNextSiblingOf( IMovableLocation location ) + { + return location.CanMoveBefore( this ); + } + + protected override bool CanBePreviousSiblingOf( IMovableLocation location ) + { + return location.CanMoveAfter( this ); + } + + protected override bool CanBeParentOf( IMovableLocation location ) + { + return location.CanMoveUnder( this ); + } + + protected override void SetHasNextSiblingOf( IMovableLocation location ) + { + location.MoveBefore( this ); + } + + protected override void SetHasPreviousSiblingOf( IMovableLocation location ) + { + location.MoveAfter( this ); + } + + protected override void SetHasParentOf( IMovableLocation location ) + { + location.MoveUnder( this ); + } + + internal override int EnsureLocation() + { + return this.Owner.EnsureOrphan( m_level, this.Index ); + } + + private readonly int m_level; + } + + #endregion + + #region ColumnLocation Private Class + + private sealed class ColumnLocation : Location, IColumnLocation + { + internal ColumnLocation( ColumnHierarchyModel owner, TColumn column, int hashCode, int index ) + : base( owner, index ) + { + m_column = column; + m_hashCode = hashCode; + } + + protected override LocationType Type + { + get + { + return LocationType.Column; + } + } + + TColumn IColumnLocation.Column + { + get + { + return m_column; + } + } + + TStatus IColumnLocation.Status + { + get + { + return this.GetStatus(); + } + set + { + this.SetStatus( value ); + } + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public override bool Equals( object obj ) + { + var target = obj as ColumnLocation; + if( target == null ) + return false; + + return ( object.Equals( m_column, target.m_column ) ) + && ( base.Equals( target ) ); + } + + protected override bool CanMoveBefore( ColumnLocation location ) + { + return true; + } + + protected override bool CanMoveBefore( SplitterLocation location ) + { + // The column may move only next to the the top-most splitter. + return location.IsMovable; + } + + protected override bool CanMoveBefore( OrphanLocation location ) + { + return true; + } + + protected override bool CanMoveAfter( ColumnLocation location ) + { + return true; + } + + protected override bool CanMoveAfter( SplitterLocation location ) + { + // The column may move only next to the the top-most splitter. + return location.IsMovable; + } + + protected override bool CanMoveAfter( StartLocation location ) + { + return true; + } + + protected override bool CanMoveUnder( ColumnLocation location ) + { + return true; + } + + protected override bool CanMoveUnder( OrphanLocation location ) + { + return true; + } + + protected override void MoveBefore( ColumnLocation location ) + { + this.MoveBeforeCore( location ); + } + + protected override void MoveBefore( SplitterLocation location ) + { + this.MoveBeforeCore( location ); + } + + protected override void MoveBefore( OrphanLocation location ) + { + this.MoveBeforeCore( location ); + } + + protected override void MoveAfter( ColumnLocation location ) + { + this.MoveAfterCore( location ); + } + + protected override void MoveAfter( SplitterLocation location ) + { + this.MoveAfterCore( location ); + } + + protected override void MoveAfter( StartLocation location ) + { + this.MoveAfterCore( location ); + } + + protected override void MoveUnder( ColumnLocation location ) + { + this.MoveUnderCore( location ); + } + + protected override void MoveUnder( OrphanLocation location ) + { + this.MoveUnderCore( location ); + } + + protected override bool CanBeNextSiblingOf( IMovableLocation location ) + { + return location.CanMoveBefore( this ); + } + + protected override bool CanBePreviousSiblingOf( IMovableLocation location ) + { + return location.CanMoveAfter( this ); + } + + protected override bool CanBeParentOf( IMovableLocation location ) + { + return location.CanMoveUnder( this ); + } + + protected override void SetHasNextSiblingOf( IMovableLocation location ) + { + location.MoveBefore( this ); + } + + protected override void SetHasPreviousSiblingOf( IMovableLocation location ) + { + location.MoveAfter( this ); + } + + protected override void SetHasParentOf( IMovableLocation location ) + { + location.MoveUnder( this ); + } + + internal override int EnsureLocation() + { + return this.Owner.EnsureColumn( m_column, m_hashCode, this.Index ); + } + + private readonly TColumn m_column; + private readonly int m_hashCode; + } + + #endregion + + #region ColumnEntry Private Struct + + [DebuggerDisplay( "Column = {Column}, Next = {Next}" )] + private struct ColumnEntry + { + internal ColumnEntry( TColumn column, int hashCode, int next ) + { + m_column = column; + m_hashCode = hashCode; + m_next = next; + } + + internal ColumnEntry( int next ) + : this( default( TColumn ), 0, next ) + { + } + + internal TColumn Column + { + get + { + return m_column; + } + } + + internal int HashCode + { + get + { + return m_hashCode; + } + } + + internal int Next + { + get + { + return m_next; + } + } + + internal ColumnEntry SetNext( int next ) + { + return new ColumnEntry( m_column, m_hashCode, next ); + } + + private readonly TColumn m_column; + private readonly int m_hashCode; + private readonly int m_next; + } + + #endregion + + #region MarkEntry Private Struct + + [DebuggerDisplay( "Start = {Start}, End = {End}, Splitter = {Splitter}, Orphan = {Orphan}" )] + private struct MarkEntry + { + internal static readonly MarkEntry Default = new MarkEntry( ColumnHierarchyModel.None, ColumnHierarchyModel.None, ColumnHierarchyModel.None, ColumnHierarchyModel.None ); + + internal MarkEntry( int start, int end, int splitter, int orphan ) + { + m_start = start; + m_end = end; + m_splitter = splitter; + m_orphan = orphan; + } + + internal int Start + { + get + { + return m_start; + } + } + + internal int End + { + get + { + return m_end; + } + } + + internal int Splitter + { + get + { + return m_splitter; + } + } + + internal int Orphan + { + get + { + return m_orphan; + } + } + + private readonly int m_start; + private readonly int m_end; + private readonly int m_splitter; + private readonly int m_orphan; + } + + #endregion + + #region RelationEntry Private Struct + + [DebuggerDisplay( "Parent = {Parent}, FirstChild = {FirstChild}, Previous = {Previous}, Next = {Next}" )] + private struct RelationEntry + { + internal static readonly RelationEntry Default = new RelationEntry( ColumnHierarchyModel.None, ColumnHierarchyModel.None ); + + internal RelationEntry( int parent, int child, int previous, int next ) + { + m_previous = previous; + m_next = next; + m_parent = parent; + m_child = child; + } + + internal RelationEntry( int child, int previous, int next ) + : this( ColumnHierarchyModel.None, child, previous, next ) + { + } + + internal RelationEntry( int previous, int next ) + : this( ColumnHierarchyModel.None, previous, next ) + { + } + + internal int Parent + { + get + { + return m_parent; + } + } + + internal int FirstChild + { + get + { + return m_child; + } + } + + internal int Previous + { + get + { + return m_previous; + } + } + + internal int Next + { + get + { + return m_next; + } + } + + internal RelationEntry SetParent( int parent ) + { + return new RelationEntry( parent, m_child, m_previous, m_next ); + } + + internal RelationEntry SetFirstChild( int child ) + { + return new RelationEntry( m_parent, child, m_previous, m_next ); + } + + internal RelationEntry SetPrevious( int previous ) + { + return new RelationEntry( m_parent, m_child, previous, m_next ); + } + + internal RelationEntry SetNext( int next ) + { + return new RelationEntry( m_parent, m_child, m_previous, next ); + } + + private readonly int m_previous; + private readonly int m_next; + private readonly int m_parent; + private readonly int m_child; + } + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnManagerCell.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnManagerCell.cs index 7474089a..3704d7fb 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnManagerCell.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnManagerCell.cs @@ -14,8 +14,10 @@ ***********************************************************************************/ +using System; using System.ComponentModel; using System.Diagnostics; +using System.Globalization; using System.Windows; using System.Windows.Automation.Peers; using System.Windows.Controls.Primitives; @@ -24,7 +26,6 @@ using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using Xceed.Utils.Wpf.DragDrop; -using Xceed.Wpf.DataGrid.Automation; using Xceed.Wpf.DataGrid.Views; namespace Xceed.Wpf.DataGrid @@ -35,8 +36,8 @@ namespace Xceed.Wpf.DataGrid { static ColumnManagerCell() { - FocusableProperty.OverrideMetadata( typeof( ColumnManagerCell ), new FrameworkPropertyMetadata( false ) ); - ReadOnlyProperty.OverrideMetadata( typeof( ColumnManagerCell ), new FrameworkPropertyMetadata( true ) ); + UIElement.FocusableProperty.OverrideMetadata( typeof( ColumnManagerCell ), new FrameworkPropertyMetadata( false ) ); + Cell.ReadOnlyProperty.OverrideMetadata( typeof( ColumnManagerCell ), new FrameworkPropertyMetadata( true ) ); ColumnManagerCell.IsPressedProperty = ColumnManagerCell.IsPressedPropertyKey.DependencyProperty; @@ -151,13 +152,26 @@ namespace Xceed.Wpf.DataGrid #endregion - #region ColumnReordering Internal Event + #region CanBeCollapsed Property - internal static readonly RoutedEvent ColumnReorderingEvent = - EventManager.RegisterRoutedEvent( "ColumnReordering", - RoutingStrategy.Bubble, - typeof( ColumnReorderingEventHandler ), - typeof( ColumnManagerCell ) ); + internal override bool CanBeCollapsed + { + get + { + // A ColumnManagerCell is always collapsible (except when it, or it's parent column, is being dragged), since it can't be edited. + if( ( bool )this.GetValue( ColumnManagerCell.IsBeingDraggedProperty ) ) + { + return false; + } + + var parentColumn = this.ParentColumn; + if( parentColumn == null ) + return true; + + return !TableflowView.GetIsBeingDraggedAnimated( parentColumn ); + + } + } #endregion @@ -172,15 +186,11 @@ namespace Xceed.Wpf.DataGrid { base.InitializeCore( dataGridContext, parentRow, parentColumn ); - this.SetColumnBinding( ColumnManagerCell.ContentProperty, parentColumn, ColumnBase.TitleProperty ); - this.SetColumnBinding( ColumnManagerCell.ContentTemplateProperty, parentColumn, ColumnBase.TitleTemplateProperty ); - this.SetColumnBinding( ColumnManagerCell.ContentTemplateSelectorProperty, parentColumn, ColumnBase.TitleTemplateSelectorProperty ); + this.SetColumnBinding( ColumnManagerCell.ContentProperty, "ParentColumn.Title" ); + this.SetColumnBinding( ColumnManagerCell.ContentTemplateProperty, "ParentColumn.TitleTemplate" ); + this.SetColumnBinding( ColumnManagerCell.ContentTemplateSelectorProperty, "ParentColumn.TitleTemplateSelector" ); } - protected override AutomationPeer OnCreateAutomationPeer() - { - return new ColumnManagerCellAutomationPeer( this ); - } protected internal override void PrepareDefaultStyleKey( ViewBase view ) { @@ -226,8 +236,7 @@ namespace Xceed.Wpf.DataGrid UIViewBase uiViewBase = dataGridContext.DataGridControl.GetView() as UIViewBase; m_dragSourceManager.DropOutsideCursor = ( uiViewBase != null ) ? uiViewBase.CannotDropDraggedElementCursor : UIViewBase.DefaultCannotDropDraggedElementCursor; - - m_dragSourceManager.ProcessMouseLeftButtonDown( e ); + m_dragSourceManager.DragStart( e ); } } @@ -243,7 +252,7 @@ namespace Xceed.Wpf.DataGrid { if( m_dragSourceManager != null ) { - m_dragSourceManager.ProcessMouseMove( e ); + m_dragSourceManager.DragMove( e ); } if( !this.IsBeingDragged ) @@ -270,7 +279,7 @@ namespace Xceed.Wpf.DataGrid if( m_dragSourceManager != null ) { - m_dragSourceManager.ProcessMouseLeftButtonUp( e ); + m_dragSourceManager.Drop( e ); } if( isMouseCaptured ) @@ -312,7 +321,7 @@ namespace Xceed.Wpf.DataGrid { if( m_dragSourceManager != null ) { - m_dragSourceManager.ProcessLostMouseCapture( e ); + m_dragSourceManager.DragCancel( e ); } if( this.IsPressed ) @@ -367,8 +376,6 @@ namespace Xceed.Wpf.DataGrid Debug.Assert( dataGridContext != null ); var toggleColumnSortCommand = dataGridContext.ToggleColumnSortCommand; - if( !toggleColumnSortCommand.CanExecute( column, shiftUnpressed ) ) - return; toggleColumnSortCommand.Execute( column, shiftUnpressed ); } @@ -433,7 +440,7 @@ namespace Xceed.Wpf.DataGrid m_originalWidth = -1d; } - internal void ShowDropMark( Point mousePosition ) + internal void ShowDropMark( RelativePoint mousePosition ) { if( m_dropMarkAdorner == null ) { @@ -532,9 +539,9 @@ namespace Xceed.Wpf.DataGrid private void SetupDragManager() { + // Prevent any drag operation if columns layout is changing. var dataGridContext = this.DataGridContext; - // Can be null in design-time (edition of a style TargetType ColumnManagerCell). - if( dataGridContext == null ) + if( ( dataGridContext == null ) || ( dataGridContext.ColumnManager.IsUpdateDeferred ) ) return; // We do not support DragDrop when there are no AdornerLayer because there wouldn't be any visual feedback for the operation. @@ -553,8 +560,7 @@ namespace Xceed.Wpf.DataGrid } var dataGridControl = dataGridContext.DataGridControl; - if( dataGridControl == null ) - return; + Debug.Assert( dataGridControl != null ); if( m_dragSourceManager != null ) { @@ -579,13 +585,14 @@ namespace Xceed.Wpf.DataGrid binding.Path = new PropertyPath( "(0).(1)", DataGridControl.DataGridContextProperty, TableView.AutoScrollIntervalProperty ); binding.Mode = BindingMode.OneWay; binding.Source = this; + binding.Converter = new MillisecondsConverter(); BindingOperations.SetBinding( m_dragSourceManager, DragSourceManager.AutoScrollIntervalProperty, binding ); binding = new Binding(); - binding.Path = new PropertyPath( "(0).(1)", DataGridControl.DataGridContextProperty, TableView.AutoScrollTresholdProperty ); + binding.Path = new PropertyPath( "(0).(1)", DataGridControl.DataGridContextProperty, TableView.AutoScrollThresholdProperty ); binding.Mode = BindingMode.OneWay; binding.Source = this; - BindingOperations.SetBinding( m_dragSourceManager, DragSourceManager.AutoScrollTresholdProperty, binding ); + BindingOperations.SetBinding( m_dragSourceManager, DragSourceManager.AutoScrollThresholdProperty, binding ); } private void DragSourceManager_PropertyChanged( object sender, PropertyChangedEventArgs e ) @@ -663,7 +670,11 @@ namespace Xceed.Wpf.DataGrid private ColumnManagerCell GetPreviousVisibleColumnManagerCell() { - var previousVisibleColumn = this.ParentColumn.PreviousVisibleColumn; + var parentColumn = this.ParentColumn; + if( parentColumn == null ) + return null; + + var previousVisibleColumn = parentColumn.PreviousVisibleColumn; if( previousVisibleColumn == null ) return null; @@ -715,12 +726,12 @@ namespace Xceed.Wpf.DataGrid previousColumnManagerCell.ColumnResizerThumb_DragCompleted( previousColumnManagerCell, e ); } - private void SetColumnBinding( DependencyProperty targetProperty, ColumnBase parentColumn, DependencyProperty sourceProperty ) + private void SetColumnBinding( DependencyProperty targetProperty, string sourceProperty ) { - if( this.HasColumnBinding( targetProperty, parentColumn, sourceProperty ) ) + if( BindingOperations.GetBinding( this, targetProperty ) != null ) return; - var binding = ColumnManagerCell.CreateColumnBinding( parentColumn, sourceProperty ); + var binding = ColumnManagerCell.CreateColumnBinding( sourceProperty ); if( binding != null ) { BindingOperations.SetBinding( this, targetProperty, binding ); @@ -731,35 +742,12 @@ namespace Xceed.Wpf.DataGrid } } - private bool HasColumnBinding( DependencyProperty targetProperty, ColumnBase parentColumn, DependencyProperty sourceProperty ) - { - if( parentColumn == null ) - return false; - - var binding = BindingOperations.GetBinding( this, targetProperty ); - if( binding == null ) - return false; - - var path = binding.Path; - if( path == null ) - return false; - - var pathParameters = path.PathParameters; - - return ( binding.Source == parentColumn ) - && ( pathParameters.Count == 1 ) - && ( pathParameters[ 0 ] == sourceProperty ); - } - - private static Binding CreateColumnBinding( ColumnBase parentColumn, DependencyProperty sourceProperty ) + private static Binding CreateColumnBinding( string sourceProperty ) { - if( parentColumn == null ) - return null; - var binding = new Binding(); binding.Path = new PropertyPath( sourceProperty ); binding.Mode = BindingMode.OneWay; - binding.Source = parentColumn; + binding.RelativeSource = new RelativeSource( RelativeSourceMode.Self ); binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; return binding; @@ -767,38 +755,63 @@ namespace Xceed.Wpf.DataGrid #region IDropTarget Members - bool IDropTarget.CanDropElement( UIElement draggedElement ) + bool IDropTarget.CanDropElement( UIElement draggedElement, RelativePoint mousePosition ) { - ColumnManagerCell draggedCell = draggedElement as ColumnManagerCell; + var draggedCell = draggedElement as ColumnManagerCell; if( ( draggedCell == null ) || ( this == draggedCell ) ) return false; - ColumnManagerRow parentRow = this.ParentRow as ColumnManagerRow; + var parentRow = this.ParentRow as ColumnManagerRow; if( ( parentRow == null ) || !parentRow.AllowColumnReorder ) return false; - if( !ColumnManagerCell.CanMove( draggedCell ) || !ColumnManagerCell.CanMove( this ) ) + var draggedDetailContext = draggedCell.DataGridContext; + var sourceDetailContext = this.DataGridContext; + Debug.Assert( ( draggedDetailContext != null ) && ( sourceDetailContext != null ) ); + + if( ( sourceDetailContext.SourceDetailConfiguration != draggedDetailContext.SourceDetailConfiguration ) || + ( sourceDetailContext.GroupLevelDescriptions != draggedDetailContext.GroupLevelDescriptions ) ) return false; - DataGridContext draggedDetailContext = draggedCell.DataGridContext; - DataGridContext sourceDetailContext = this.DataGridContext; - Debug.Assert( ( draggedDetailContext != null ) && ( sourceDetailContext != null ) ); + if( !ColumnManagerCell.CanMove( draggedCell ) ) + return false; + + var manager = draggedCell.DragSourceManager as ColumnReorderingDragSourceManager; + if( ( manager != null ) && ( manager.IsAnimatedColumnReorderingEnabled ) ) + { + if( !manager.CanReorder( draggedCell, this, mousePosition ) ) + return false; + } + else + { + var relativePosition = mousePosition.GetPoint( this ); + var moveBefore = ( relativePosition.X <= this.ActualWidth / 2d ); - return ( sourceDetailContext.SourceDetailConfiguration == draggedDetailContext.SourceDetailConfiguration ) && - ( sourceDetailContext.GroupLevelDescriptions == draggedDetailContext.GroupLevelDescriptions ); + if( moveBefore ) + { + if( !draggedCell.CanMoveBefore( this.ParentColumn ) ) + return false; + } + else + { + if( !draggedCell.CanMoveAfter( this.ParentColumn ) ) + return false; + } + } + + return true; } void IDropTarget.DragEnter( UIElement draggedElement ) { } - void IDropTarget.DragOver( UIElement draggedElement, Point mousePosition ) + void IDropTarget.DragOver( UIElement draggedElement, RelativePoint mousePosition ) { - ColumnManagerCell draggedCell = draggedElement as ColumnManagerCell; - + var draggedCell = draggedElement as ColumnManagerCell; if( draggedCell != null ) { - ColumnReorderingDragSourceManager manager = draggedCell.DragSourceManager as ColumnReorderingDragSourceManager; + var manager = draggedCell.DragSourceManager as ColumnReorderingDragSourceManager; // No need for drop mark when performing animated Column reordering if( ( manager != null ) && ( manager.IsAnimatedColumnReorderingEnabled ) ) @@ -810,11 +823,10 @@ namespace Xceed.Wpf.DataGrid void IDropTarget.DragLeave( UIElement draggedElement ) { - ColumnManagerCell draggedCell = draggedElement as ColumnManagerCell; - + var draggedCell = draggedElement as ColumnManagerCell; if( draggedCell != null ) { - ColumnReorderingDragSourceManager manager = draggedCell.DragSourceManager as ColumnReorderingDragSourceManager; + var manager = draggedCell.DragSourceManager as ColumnReorderingDragSourceManager; // No need for drop mark when performing animated Column reordering if( ( manager != null ) && ( manager.IsAnimatedColumnReorderingEnabled ) ) @@ -824,19 +836,18 @@ namespace Xceed.Wpf.DataGrid this.HideDropMark(); } - void IDropTarget.Drop( UIElement draggedElement ) + void IDropTarget.Drop( UIElement draggedElement, RelativePoint mousePosition ) { - ColumnManagerCell draggedCell = draggedElement as ColumnManagerCell; - + var draggedCell = draggedElement as ColumnManagerCell; if( draggedCell == null ) return; - this.ProcessDrop( draggedCell ); + this.ProcessDrop( draggedCell, mousePosition ); } - internal void ProcessDrop( ColumnManagerCell draggedCell ) + internal void ProcessDrop( ColumnManagerCell draggedCell, RelativePoint mousePosition ) { - ColumnReorderingDragSourceManager manager = null; + var manager = default( ColumnReorderingDragSourceManager ); if( draggedCell != null ) { @@ -849,47 +860,110 @@ namespace Xceed.Wpf.DataGrid } else { - int oldPosition = draggedCell.ParentColumn.VisiblePosition; - int newPosition = this.ParentColumn.VisiblePosition; + this.HideDropMark(); - if( m_dropMarkAdorner != null ) + var dataGridContext = this.DataGridContext; + Debug.Assert( dataGridContext != null ); + + if( dataGridContext != null ) { - DropMarkAlignment alignment = m_dropMarkAdorner.Alignment; + var targetColumn = draggedCell.ParentColumn; + var pivotColumn = this.ParentColumn; + + Debug.Assert( targetColumn != null ); + Debug.Assert( pivotColumn != null ); - this.HideDropMark(); + var relativePosition = mousePosition.GetPoint( this ); + var offset = Point.Subtract( mousePosition.GetPoint( draggedCell ), relativePosition ); + var moveBefore = true; - if( draggedCell.ParentColumn.VisiblePosition < newPosition ) + // We assumme the cells are layouted horizontally. + if( Math.Abs( offset.X ) >= Math.Abs( offset.Y ) ) { - if( alignment == DropMarkAlignment.Near ) - { - draggedCell.ParentColumn.VisiblePosition = newPosition - 1; - } - else - { - draggedCell.ParentColumn.VisiblePosition = newPosition; - } + // Consider the case where the columns are layouted from left to right in reverse order. + var reverse = ( ( offset.X > 0d ) == ( targetColumn.VisiblePosition >= pivotColumn.VisiblePosition ) ); + + moveBefore = ( ( relativePosition.X < this.ActualWidth / 2d ) != reverse ); } + // We assume the cells are layouted vertically. else { - if( alignment == DropMarkAlignment.Near ) - { - draggedCell.ParentColumn.VisiblePosition = newPosition; - } - else - { - draggedCell.ParentColumn.VisiblePosition = newPosition + 1; - } + // Consider the case where the columns are layouted from top to bottom in reverse order. + var reverse = ( ( offset.Y > 0d ) == ( targetColumn.VisiblePosition >= pivotColumn.VisiblePosition ) ); + + moveBefore = ( ( relativePosition.Y < this.ActualHeight / 2d ) != reverse ); } - // This will force every Rows to update there layout - ColumnReorderingEventArgs e = new ColumnReorderingEventArgs( ColumnManagerCell.ColumnReorderingEvent, oldPosition, newPosition ); - this.RaiseEvent( e ); + var success = ( moveBefore ) + ? dataGridContext.MoveColumnBefore( targetColumn, pivotColumn ) + : dataGridContext.MoveColumnAfter( targetColumn, pivotColumn ); + Debug.Assert( success ); } } } - private static bool CanMove( ColumnManagerCell cell ) + internal bool CanMoveBefore( ColumnBase column ) + { + // A column that is locked cannot move. + var parentColumn = this.ParentColumn; + if( ( parentColumn == null ) || ( parentColumn.DraggableStatus != ColumnDraggableStatus.Draggable ) ) + return false; + + // The cell cannot move before a column that is locked in the first position. + if( ( column == null ) || ( column.DraggableStatus == ColumnDraggableStatus.FirstUndraggable ) ) + return false; + + var dataGridContext = this.DataGridContext; + if( dataGridContext == null ) + return false; + + if( dataGridContext.AreDetailsFlatten ) + { + // Column reordering is not allowed for a ColumnManagerCell that is located at a detail level + // when details are flatten. + if( dataGridContext.SourceDetailConfiguration != null ) + return false; + + // The main column is always the first column when details are flatten. + if( column.IsMainColumn ) + return false; + } + + return true; + } + + internal bool CanMoveAfter( ColumnBase column ) + { + // A column that is locked cannot move. + var parentColumn = this.ParentColumn; + if( ( parentColumn == null ) || ( parentColumn.DraggableStatus != ColumnDraggableStatus.Draggable ) ) + return false; + + // The cell cannot move after a column that is locked in the last position. + if( ( column == null ) || ( column.DraggableStatus == ColumnDraggableStatus.LastUndraggable ) ) + return false; + + var dataGridContext = this.DataGridContext; + if( dataGridContext == null ) + return false; + + if( dataGridContext.AreDetailsFlatten ) + { + // Column reordering is not allowed for a ColumnManagerCell that is located at a detail level + // when details are flatten. + if( dataGridContext.SourceDetailConfiguration != null ) + return false; + + // The main column is not allowed to be reordered when details are flatten. + if( column.IsMainColumn ) + return false; + } + + return true; + } + + internal static bool CanMove( ColumnManagerCell cell ) { if( cell == null ) return false; @@ -898,6 +972,11 @@ namespace Xceed.Wpf.DataGrid if( dataGridContext == null ) return false; + // A column that is locked cannot move. + var parentColumn = cell.ParentColumn; + if( ( parentColumn == null ) || ( parentColumn.DraggableStatus != ColumnDraggableStatus.Draggable ) ) + return false; + if( dataGridContext.AreDetailsFlatten ) { // Column reordering is not allowed for a ColumnManagerCell that is located at a detail level @@ -906,15 +985,14 @@ namespace Xceed.Wpf.DataGrid return false; // The main column is not allowed to be reordered when details are flatten. - var parentColumn = cell.ParentColumn; - if( ( parentColumn == null ) || ( parentColumn.IsMainColumn ) ) + if( parentColumn.IsMainColumn ) return false; } return true; } - #endregion IDropTarget Members + #endregion // Will remain null when no AdornerLayer is found. private ColumnReorderingDragSourceManager m_dragSourceManager; @@ -927,5 +1005,22 @@ namespace Xceed.Wpf.DataGrid private double m_originalWidth = -1d; private Thumb m_columnResizerThumb; // = null private Thumb m_columnResizerThumbLeft; // null + + #region MillisecondsConverter Private Class + + private sealed class MillisecondsConverter : IValueConverter + { + public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) + { + return TimeSpan.FromMilliseconds( System.Convert.ToDouble( value ) ); + } + + public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) + { + throw new NotSupportedException(); + } + } + + #endregion } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnManagerRow.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnManagerRow.cs index 210dcf62..9f19429b 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnManagerRow.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnManagerRow.cs @@ -14,13 +14,18 @@ ***********************************************************************************/ +using System; using System.Collections; -using System.Diagnostics; +using System.ComponentModel; +using System.Linq; using System.Windows; using System.Windows.Automation.Peers; -using Xceed.Wpf.DataGrid.Automation; -using Xceed.Wpf.DataGrid.Views; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Input; +using Xceed.Utils.Wpf; using Xceed.Utils.Wpf.DragDrop; +using Xceed.Wpf.DataGrid.Views; namespace Xceed.Wpf.DataGrid { @@ -28,7 +33,8 @@ namespace Xceed.Wpf.DataGrid { static ColumnManagerRow() { - NavigationBehaviorProperty.OverrideMetadata( typeof( ColumnManagerRow ), new FrameworkPropertyMetadata( NavigationBehavior.None ) ); + Row.NavigationBehaviorProperty.OverrideMetadata( typeof( ColumnManagerRow ), new FrameworkPropertyMetadata( NavigationBehavior.None ) ); + FrameworkElement.ContextMenuProperty.OverrideMetadata( typeof( ColumnManagerRow ), new FrameworkPropertyMetadata( null, new CoerceValueCallback( ColumnManagerRow.CoerceContextMenu ) ) ); } public ColumnManagerRow() @@ -42,8 +48,11 @@ namespace Xceed.Wpf.DataGrid #region AllowColumnReorder Property - public static readonly DependencyProperty AllowColumnReorderProperty = - DependencyProperty.Register( "AllowColumnReorder", typeof( bool ), typeof( ColumnManagerRow ), new UIPropertyMetadata( true ) ); + public static readonly DependencyProperty AllowColumnReorderProperty = DependencyProperty.Register( + "AllowColumnReorder", + typeof( bool ), + typeof( ColumnManagerRow ), + new FrameworkPropertyMetadata( true, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback( ColumnManagerRow.OnAllowColumnReorderChanged ) ) ); public bool AllowColumnReorder { @@ -57,12 +66,28 @@ namespace Xceed.Wpf.DataGrid } } - #endregion AllowColumnReorder Property + private static void OnAllowColumnReorderChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) + { + var self = sender as ColumnManagerRow; + if( self == null ) + return; + + var configuration = self.Configuration; + if( configuration == null ) + return; + + configuration.AllowColumnReorder = ( bool )e.NewValue; + } + + #endregion #region AllowColumnResize Property - public static readonly DependencyProperty AllowColumnResizeProperty = - DependencyProperty.Register( "AllowColumnResize", typeof( bool ), typeof( ColumnManagerRow ), new UIPropertyMetadata( true ) ); + public static readonly DependencyProperty AllowColumnResizeProperty = DependencyProperty.Register( + "AllowColumnResize", + typeof( bool ), + typeof( ColumnManagerRow ), + new UIPropertyMetadata( true ) ); public bool AllowColumnResize { @@ -76,12 +101,15 @@ namespace Xceed.Wpf.DataGrid } } - #endregion AllowColumnResize Property + #endregion #region AllowSort Property - public static readonly DependencyProperty AllowSortProperty = - DependencyProperty.Register( "AllowSort", typeof( bool ), typeof( ColumnManagerRow ), new UIPropertyMetadata( true ) ); + public static readonly DependencyProperty AllowSortProperty = DependencyProperty.Register( + "AllowSort", + typeof( bool ), + typeof( ColumnManagerRow ), + new UIPropertyMetadata( true ) ); public bool AllowSort { @@ -95,13 +123,56 @@ namespace Xceed.Wpf.DataGrid } } - #endregion AllowSort Property + #endregion + + #region IsUnfocusable Property - protected override AutomationPeer OnCreateAutomationPeer() + internal override bool IsUnfocusable { - return new ColumnManagerRowAutomationPeer( this ); + get + { + return true; + } + } + + #endregion + + #region Configuration Internal Property + + internal ColumnManagerRowConfiguration Configuration + { + get + { + return m_configuration; + } + set + { + if( value == m_configuration ) + return; + + if( m_configuration != null ) + { + PropertyChangedEventManager.RemoveListener( m_configuration, this, string.Empty ); + } + + m_configuration = value; + + this.PushAllowColumnReorder(); + + if( m_configuration != null ) + { + PropertyChangedEventManager.AddListener( m_configuration, this, string.Empty ); + } + + this.UpdateAllowColumnReorder(); + } } + private ColumnManagerRowConfiguration m_configuration; + + #endregion + + protected override Cell CreateCell( ColumnBase column ) { return new ColumnManagerCell(); @@ -112,14 +183,27 @@ namespace Xceed.Wpf.DataGrid return ( cell is ColumnManagerCell ); } - protected internal override void PrepareDefaultStyleKey( ViewBase view ) + protected internal override void PrepareDefaultStyleKey( Xceed.Wpf.DataGrid.Views.ViewBase view ) { - object currentThemeKey = view.GetDefaultStyleKey( typeof( ColumnManagerRow ) ); + var currentThemeKey = view.GetDefaultStyleKey( typeof( ColumnManagerRow ) ); + if( currentThemeKey.Equals( this.DefaultStyleKey ) ) + return; - if( currentThemeKey.Equals( this.DefaultStyleKey ) == false ) - { - this.DefaultStyleKey = currentThemeKey; - } + this.DefaultStyleKey = currentThemeKey; + } + + protected override void PrepareContainer( DataGridContext dataGridContext, object item ) + { + base.PrepareContainer( dataGridContext, item ); + + this.Configuration = dataGridContext.ColumnManagerRowConfiguration; + } + + protected override void ClearContainer() + { + this.Configuration = null; + + base.ClearContainer(); } protected override void OnPreviewMouseLeftButtonDown( System.Windows.Input.MouseButtonEventArgs e ) @@ -128,42 +212,92 @@ namespace Xceed.Wpf.DataGrid //This is because we do not want the ColumnManager Row to be selectable through the Mouse } - #region IDropTarget Members + protected override void OnMouseRightButtonUp( MouseButtonEventArgs e ) + { + if( e.Handled ) + return; + + base.OnMouseRightButtonUp( e ); + } - bool IDropTarget.CanDropElement( UIElement draggedElement ) + private static object CoerceContextMenu( DependencyObject sender, object value ) { - bool canDrop = false; + if( value == null ) + return value; - ColumnManagerCell draggedCell = draggedElement as ColumnManagerCell; + var self = sender as ColumnManagerRow; + if( ( self == null ) ) + return value; - if( draggedCell == null ) - return false; + return null; + } - ColumnReorderingDragSourceManager manager = draggedCell.DragSourceManager as ColumnReorderingDragSourceManager; + private void PushAllowColumnReorder() + { + var configuration = this.Configuration; + if( configuration == null ) + return; - if( ( manager != null ) && ( manager.IsAnimatedColumnReorderingEnabled ) ) + if( DependencyPropertyHelper.GetValueSource( this, ColumnManagerRow.AllowColumnReorderProperty ).BaseValueSource == BaseValueSource.Default ) + return; + + configuration.AllowColumnReorder = this.AllowColumnReorder; + } + + private void UpdateAllowColumnReorder() + { + var configuration = this.Configuration; + if( configuration == null ) + return; + + this.AllowColumnReorder = configuration.AllowColumnReorder; + } + + private void OnConfigurationPropertyChanged( PropertyChangedEventArgs e ) + { + var propertyName = e.PropertyName; + + if( string.IsNullOrEmpty( propertyName ) || propertyName == ColumnManagerRow.AllowColumnReorderProperty.Name ) { - ColumnManagerCell cell = draggedElement as ColumnManagerCell; + this.UpdateAllowColumnReorder(); + } + } - if( ( cell != null ) && ( cell.IsBeingDragged ) ) - { - DataGridContext rowDataGridContext = DataGridControl.GetDataGridContext( this ); + #region IDropTarget Members - if( ( rowDataGridContext != null ) && ( rowDataGridContext.Columns.Contains( cell.ParentColumn ) ) ) - { - canDrop = true; - } - } + bool IDropTarget.CanDropElement( UIElement draggedElement, RelativePoint mousePosition ) + { + var draggedCell = draggedElement as ColumnManagerCell; + if( draggedCell == null ) + return false; + + var manager = draggedCell.DragSourceManager as ColumnReorderingDragSourceManager; + if( ( manager != null ) && manager.IsAnimatedColumnReorderingEnabled && draggedCell.IsBeingDragged ) + { + var dataGridContext = DataGridControl.GetDataGridContext( this ); + if( ( dataGridContext == null ) || !dataGridContext.Columns.Contains( draggedCell.ParentColumn ) ) + return false; + + // We are not interested by the y-axis. + var relativePoint = mousePosition.GetPoint( this ); + var xPosition = new RelativePoint( this, new Point( relativePoint.X, this.ActualHeight / 2d ) ); + + var targetCell = ( from dropTarget in manager.GetDropTargetsAtPoint( xPosition ) + let dropCell = dropTarget as ColumnManagerCell + where ( dropCell != null ) + select dropCell ).FirstOrDefault(); + if( ( targetCell == null ) || ( targetCell == draggedCell ) || ( ( IDropTarget )targetCell ).CanDropElement( draggedElement, xPosition ) ) + return true; } - return canDrop; + return false; } void IDropTarget.DragEnter( UIElement draggedElement ) { } - void IDropTarget.DragOver( UIElement draggedElement, Point mousePosition ) + void IDropTarget.DragOver( UIElement draggedElement, RelativePoint mousePosition ) { } @@ -171,15 +305,13 @@ namespace Xceed.Wpf.DataGrid { } - void IDropTarget.Drop( UIElement draggedElement ) + void IDropTarget.Drop( UIElement draggedElement, RelativePoint mousePosition ) { - ColumnManagerCell draggedCell = draggedElement as ColumnManagerCell; - + var draggedCell = draggedElement as ColumnManagerCell; if( draggedCell == null ) return; - ColumnReorderingDragSourceManager manager = draggedCell.DragSourceManager as ColumnReorderingDragSourceManager; - + var manager = draggedCell.DragSourceManager as ColumnReorderingDragSourceManager; if( ( manager != null ) && ( manager.IsAnimatedColumnReorderingEnabled ) ) { manager.CommitReordering(); @@ -187,5 +319,28 @@ namespace Xceed.Wpf.DataGrid } #endregion + + #region IWeakEventListener Members + + protected override bool OnReceiveWeakEvent( Type managerType, object sender, EventArgs e ) + { + var result = base.OnReceiveWeakEvent( managerType, sender, e ); + + if( typeof( PropertyChangedEventManager ) == managerType ) + { + if( sender == m_configuration ) + { + this.OnConfigurationPropertyChanged( ( PropertyChangedEventArgs )e ); + } + } + else + { + return result; + } + + return true; + } + + #endregion } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnManagerRowConfiguration.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnManagerRowConfiguration.cs new file mode 100644 index 00000000..81fbab68 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnManagerRowConfiguration.cs @@ -0,0 +1,67 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System.ComponentModel; +using System.Windows; + +namespace Xceed.Wpf.DataGrid +{ + internal class ColumnManagerRowConfiguration : DependencyObject, INotifyPropertyChanged + { + #region AllowColumnReorder Property + + public static readonly DependencyProperty AllowColumnReorderProperty = DependencyProperty.Register( + "AllowColumnReorder", + typeof( bool ), + typeof( ColumnManagerRowConfiguration ), + new UIPropertyMetadata( true ) ); + + public bool AllowColumnReorder + { + get + { + return ( bool )this.GetValue( ColumnManagerRowConfiguration.AllowColumnReorderProperty ); + } + set + { + this.SetValue( ColumnManagerRowConfiguration.AllowColumnReorderProperty, value ); + } + } + + #endregion + + protected override void OnPropertyChanged( DependencyPropertyChangedEventArgs e ) + { + base.OnPropertyChanged( e ); + this.OnPropertyChanged( e.Property.Name ); + } + + #region INotifyPropertyChanged Members + + public event PropertyChangedEventHandler PropertyChanged; + + protected virtual void OnPropertyChanged( string propertyName ) + { + var handler = this.PropertyChanged; + if( handler == null ) + return; + + handler.Invoke( this, new PropertyChangedEventArgs( propertyName ) ); + } + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnReorderingEvent.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnReorderingEvent.cs deleted file mode 100644 index 9d9b1189..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnReorderingEvent.cs +++ /dev/null @@ -1,73 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Windows; - -namespace Xceed.Wpf.DataGrid -{ - internal delegate void ColumnReorderingEventHandler( object sender, ColumnReorderingEventArgs e ); - - internal class ColumnReorderingEventArgs : RoutedEventArgs - { - #region Constructors - - public ColumnReorderingEventArgs( RoutedEvent routedEvent, int oldVisiblePosition, int newVisiblePosition ) - : base( routedEvent ) - { - m_oldVisiblePosition = oldVisiblePosition; - m_newVisiblePosition = newVisiblePosition; - } - - #endregion - - #region OldVisiblePosition - - public int OldVisiblePosition - { - get - { - return m_oldVisiblePosition; - } - set - { - m_oldVisiblePosition = value; - } - } - - private int m_oldVisiblePosition; - - #endregion - - #region NewVisiblePosition - - public int NewVisiblePosition - { - get - { - return m_newVisiblePosition; - } - set - { - m_newVisiblePosition = value; - } - } - - private int m_newVisiblePosition; - - #endregion - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnSynchronizationManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnSynchronizationManager.cs index 69198547..8e8ded1f 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnSynchronizationManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ColumnSynchronizationManager.cs @@ -20,23 +20,15 @@ using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; using System.Linq; -using System.Threading; using System.Windows; using System.Windows.Data; +using Xceed.Utils.Wpf; using Xceed.Wpf.DataGrid.Views; namespace Xceed.Wpf.DataGrid { internal sealed class ColumnSynchronizationManager : IWeakEventListener { - #region Static Fields - - private static readonly string DetailConfigurationDataGridControlPropertyName = "DataGridControl"; - private static readonly string DetailConfigurationIsAttachedToDetailDescriptionPropertyName = "IsAttachedToDetailDescription"; - private static readonly string ColumnCollectionMainColumnPropertyName = "MainColumn"; - - #endregion - #region Constructor internal ColumnSynchronizationManager( DetailConfiguration configuration ) @@ -47,33 +39,18 @@ namespace Xceed.Wpf.DataGrid m_detailConfiguration = configuration; m_itemPropertyMap = configuration.ItemPropertyMap; - PropertyChangedEventManager.AddListener( configuration, this, ColumnSynchronizationManager.DetailConfigurationDataGridControlPropertyName ); - PropertyChangedEventManager.AddListener( configuration, this, ColumnSynchronizationManager.DetailConfigurationIsAttachedToDetailDescriptionPropertyName ); - CollectionChangedEventManager.AddListener( ( INotifyCollectionChanged )m_itemPropertyMap, this ); + PropertyChangedEventManager.AddListener( configuration, this, string.Empty ); + MappingChangedEventManager.AddListener( m_itemPropertyMap, this ); using( this.DeferSynchronization() ) { this.DataGridControl = configuration.DataGridControl; - this.DetailColumns = configuration.Columns; - - Debug.Assert( this.DetailColumns != null ); - } - } - - #endregion - - #region DetailConfiguration Private Property + this.DetailColumnManager = configuration.ColumnManager; - private DetailConfiguration DetailConfiguration - { - get - { - return m_detailConfiguration; + Debug.Assert( m_detailColumnManager != null ); } } - private readonly DetailConfiguration m_detailConfiguration; - #endregion #region DataGridControl Private Property @@ -102,14 +79,14 @@ namespace Xceed.Wpf.DataGrid { ViewChangedEventManager.AddListener( m_dataGridControl, this ); - this.MasterColumns = m_dataGridControl.Columns; + this.MasterColumnManager = m_dataGridControl.DataGridContext.ColumnManager; } else { - this.MasterColumns = null; + this.MasterColumnManager = null; } - this.InvalidateSynchronization(); + m_isSynchronizationValid = false; } } } @@ -118,99 +95,71 @@ namespace Xceed.Wpf.DataGrid #endregion - #region ItemPropertyMap Private Property - - private FieldNameMap ItemPropertyMap - { - get - { - return m_itemPropertyMap; - } - } - - private readonly FieldNameMap m_itemPropertyMap; - - #endregion - - #region MasterColumns Private Property + #region MasterColumnManager Private Property - private ColumnCollection MasterColumns + private ColumnHierarchyManager MasterColumnManager { get { - return m_masterColumns; + return m_masterColumnManager; } set { - if( value == m_masterColumns ) + if( value == m_masterColumnManager ) return; - if( m_masterColumns != null ) + if( m_masterColumnManager != null ) { - CollectionChangedEventManager.RemoveListener( m_masterColumns, this ); - PropertyChangedEventManager.RemoveListener( m_masterColumns, this, ColumnSynchronizationManager.ColumnCollectionMainColumnPropertyName ); - VisibleColumnsUpdatedEventManager.RemoveListener( m_masterColumns, this ); + ColumnsLayoutChangedEventManager.RemoveListener( m_masterColumnManager, this ); + CollectionChangedEventManager.RemoveListener( m_masterColumnManager.Columns, this ); + PropertyChangedEventManager.RemoveListener( m_masterColumnManager.Columns, this, ColumnCollection.MainColumnPropertyName ); } - m_masterColumns = value; + m_masterColumnManager = value; - if( m_masterColumns != null ) + if( m_masterColumnManager != null ) { - CollectionChangedEventManager.AddListener( m_masterColumns, this ); - PropertyChangedEventManager.AddListener( m_masterColumns, this, ColumnSynchronizationManager.ColumnCollectionMainColumnPropertyName ); - VisibleColumnsUpdatedEventManager.AddListener( m_masterColumns, this ); + ColumnsLayoutChangedEventManager.AddListener( m_masterColumnManager, this ); + CollectionChangedEventManager.AddListener( m_masterColumnManager.Columns, this ); + PropertyChangedEventManager.AddListener( m_masterColumnManager.Columns, this, ColumnCollection.MainColumnPropertyName ); } } } - private ColumnCollection m_masterColumns; + private ColumnHierarchyManager m_masterColumnManager; #endregion - #region DetailColumns Private Property + #region DetailColumnManager Private Property - private ColumnCollection DetailColumns + private ColumnHierarchyManager DetailColumnManager { get { - return m_detailColumns; + return m_detailColumnManager; } set { - if( value == m_detailColumns ) + if( value == m_detailColumnManager ) return; - if( m_detailColumns != null ) + if( m_detailColumnManager != null ) { - CollectionChangedEventManager.RemoveListener( m_detailColumns, this ); - VisibleColumnsUpdatedEventManager.RemoveListener( m_detailColumns, this ); + ColumnsLayoutChangedEventManager.RemoveListener( m_detailColumnManager, this ); + CollectionChangedEventManager.RemoveListener( m_detailColumnManager.Columns, this ); } - m_detailColumns = value; + m_detailColumnManager = value; - if( m_detailColumns != null ) + if( m_detailColumnManager != null ) { - CollectionChangedEventManager.AddListener( m_detailColumns, this ); - VisibleColumnsUpdatedEventManager.AddListener( m_detailColumns, this ); + ColumnsLayoutChangedEventManager.AddListener( m_detailColumnManager, this ); + CollectionChangedEventManager.AddListener( m_detailColumnManager.Columns, this ); } } } - private ColumnCollection m_detailColumns; - - #endregion - - #region PairedColumns Private Property - - private Dictionary PairedColumns - { - get - { - return m_pairedColumns; - } - } - - private readonly Dictionary m_pairedColumns = new Dictionary( 0 ); + private ColumnHierarchyManager m_detailColumnManager; #endregion @@ -220,25 +169,11 @@ namespace Xceed.Wpf.DataGrid { get { - return ( this.MasterColumns != null ) - && ( this.DetailConfiguration.IsAttachedToDetailDescription ); - } - } - - #endregion - - #region IsUpdatingColumns Private Property - - private bool IsUpdatingColumns - { - get - { - return m_isUpdatingColumns; + return ( m_masterColumnManager != null ) + && ( m_detailConfiguration.DetailDescription != null ); } } - private bool m_isUpdatingColumns; - #endregion #region AreDetailsFlatten Private Property @@ -247,10 +182,8 @@ namespace Xceed.Wpf.DataGrid { get { - var dataGridControl = this.DataGridControl; - - return ( dataGridControl != null ) - && ( dataGridControl.AreDetailsFlatten ); + return ( m_dataGridControl != null ) + && ( m_dataGridControl.AreDetailsFlatten ); } } @@ -260,47 +193,35 @@ namespace Xceed.Wpf.DataGrid private IDisposable DeferSynchronization() { - return new DeferSynchronizationHelper( this ); + return new DeferredDisposable( new DeferState( this ) ); } - private bool IsSynchronizationDefered + private bool IsSynchronizationDeferred { get { - return ( Interlocked.CompareExchange( ref m_deferSynchronizationCount, 0, 0 ) != 0 ); + return ( m_deferSynchronizationCount != 0 ); } } - private bool IsSynchronizationValid - { - get - { - return m_isSynchronizationValid; - } - } - - private void InvalidateSynchronization() - { - m_isSynchronizationValid = false; - } - private int m_deferSynchronizationCount; //0 private bool m_isSynchronizationValid = true; #endregion - private void Refresh() + internal void Refresh() { - if( this.IsUpdatingColumns ) + if( m_isUpdatingColumns ) return; - this.InvalidateSynchronization(); + m_isSynchronizationValid = false; + this.UpdateColumns(); } private void UpdateColumns() { - if( this.IsSynchronizationDefered || this.IsSynchronizationValid || this.IsUpdatingColumns ) + if( this.IsSynchronizationDeferred || m_isSynchronizationValid || m_isUpdatingColumns ) return; try @@ -310,19 +231,24 @@ namespace Xceed.Wpf.DataGrid if( this.IsSynchronizationReady && this.AreDetailsFlatten ) { - var keys = new HashSet( this.GetNewKeys() ); + Debug.Assert( m_detailColumnManager != null ); - foreach( var key in this.PairedColumns.Keys.Except( keys ).ToArray() ) + using( m_detailColumnManager.DeferUpdate() ) { - this.Desynchronize( key ); - } + var keys = new HashSet( this.GetNewKeys() ); - foreach( var key in keys.OrderBy( item => item.OrderKey ) ) - { - this.Synchronize( key ); - } + foreach( var key in m_pairedColumns.Keys.Except( keys ).ToArray() ) + { + this.Desynchronize( key ); + } + + foreach( var key in keys.OrderBy( item => item.OrderKey ) ) + { + this.Synchronize( key ); + } - this.SetMainColumn(); + this.SetMainColumn(); + } } else { @@ -340,18 +266,18 @@ namespace Xceed.Wpf.DataGrid if( key == null ) return; - var collection = this.PairedColumns; + var collection = m_pairedColumns; SynchronizationEntry pair; if( !collection.TryGetValue( key, out pair ) ) { if( key.MasterColumn != null ) { - pair = new BoundColumn( key ); + pair = new BoundColumn( this, key ); } else { - pair = new UnboundColumn( key ); + pair = new UnboundColumn( this, key ); } collection.Add( key, pair ); @@ -365,7 +291,7 @@ namespace Xceed.Wpf.DataGrid if( key == null ) return; - var collection = this.PairedColumns; + var collection = m_pairedColumns; SynchronizationEntry pair; if( !collection.TryGetValue( key, out pair ) ) @@ -377,7 +303,7 @@ namespace Xceed.Wpf.DataGrid private void Desynchronize() { - var collection = this.PairedColumns; + var collection = m_pairedColumns; while( collection.Count > 0 ) { this.Desynchronize( collection.First().Key ); @@ -389,16 +315,17 @@ namespace Xceed.Wpf.DataGrid if( !this.IsSynchronizationReady || !this.AreDetailsFlatten ) return; - var detailColumns = this.DetailColumns; - ColumnBase detailColumn = null; + Debug.Assert( m_detailColumnManager != null ); - var mainColumn = this.MasterColumns.MainColumn; + var detailColumns = m_detailColumnManager.Columns; + var detailColumn = default( ColumnBase ); + + var mainColumn = m_masterColumnManager.Columns.MainColumn; if( mainColumn != null ) { - string targetName; - if( this.ItemPropertyMap.TryGetItemPropertyName( mainColumn, out targetName ) ) + if( !DataGridItemPropertyMapHelper.TryGetDetailColumn( m_itemPropertyMap, detailColumns, mainColumn, out detailColumn ) ) { - detailColumn = detailColumns[ targetName ]; + detailColumn = null; } } @@ -407,24 +334,16 @@ namespace Xceed.Wpf.DataGrid private IEnumerable GetNewKeys() { - var detailConfig = this.DetailConfiguration; - var map = this.ItemPropertyMap; - - foreach( var detailColumn in this.DetailColumns ) + foreach( var detailColumn in m_detailColumnManager.Columns ) { - ColumnBase masterColumn; - string targetName; + var masterColumn = default( ColumnBase ); - if( map.TryGetColumnFieldName( detailColumn, out targetName ) ) - { - masterColumn = this.MasterColumns[ targetName ]; - } - else + if( !DataGridItemPropertyMapHelper.TryGetMasterColumn( m_itemPropertyMap, m_masterColumnManager.Columns, detailColumn, out masterColumn ) ) { masterColumn = null; } - yield return new SynchronizationKey( masterColumn, detailColumn, detailConfig ); + yield return new SynchronizationKey( masterColumn, detailColumn, m_detailConfiguration ); } } @@ -433,17 +352,12 @@ namespace Xceed.Wpf.DataGrid this.Refresh(); } - private void OnUserSettingsLoaded() - { - this.Refresh(); - } - private void OnMasterColumnsPropertyChanged( PropertyChangedEventArgs e ) { var propertyName = e.PropertyName; bool mayHaveChanged = string.IsNullOrEmpty( propertyName ); - if( mayHaveChanged || ( propertyName == ColumnSynchronizationManager.ColumnCollectionMainColumnPropertyName ) ) + if( mayHaveChanged || ( propertyName == ColumnCollection.MainColumnPropertyName ) ) { this.SetMainColumn(); } @@ -454,22 +368,14 @@ namespace Xceed.Wpf.DataGrid var propertyName = e.PropertyName; bool mayHaveChanged = string.IsNullOrEmpty( propertyName ); - if( mayHaveChanged || ( propertyName == ColumnSynchronizationManager.DetailConfigurationDataGridControlPropertyName ) ) - { - this.DataGridControl = this.DetailConfiguration.DataGridControl; - } - - if( mayHaveChanged || ( propertyName == ColumnSynchronizationManager.DetailConfigurationIsAttachedToDetailDescriptionPropertyName ) ) + if( mayHaveChanged || ( propertyName == DetailConfiguration.DataGridControlPropertyName ) ) { - this.Refresh(); + this.DataGridControl = m_detailConfiguration.DataGridControl; } } - private void OnItemPropertyMapCollectionChanged( NotifyCollectionChangedEventArgs e ) + private void OnItemPropertyMapMappingChanged( EventArgs e ) { - if( e.Action == NotifyCollectionChangedAction.Move ) - return; - this.Refresh(); } @@ -503,124 +409,105 @@ namespace Xceed.Wpf.DataGrid bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) { + Debug.Assert( sender != null ); + if( managerType == typeof( CollectionChangedEventManager ) ) { - if( sender == this.MasterColumns ) + if( ( m_masterColumnManager != null ) && ( sender == m_masterColumnManager.Columns ) ) { - Debug.Assert( sender != null ); - this.OnMasterColumnsCollectionChanged( ( NotifyCollectionChangedEventArgs )e ); } - else if( sender == this.DetailColumns ) + else if( ( m_detailColumnManager != null ) && ( sender == m_detailColumnManager.Columns ) ) { - Debug.Assert( sender != null ); - this.OnDetailColumnsCollectionChanged( ( NotifyCollectionChangedEventArgs )e ); } - else if( sender == this.ItemPropertyMap ) - { - Debug.Assert( sender != null ); - - this.OnItemPropertyMapCollectionChanged( ( NotifyCollectionChangedEventArgs )e ); - } - - return true; } else if( managerType == typeof( PropertyChangedEventManager ) ) { - if( sender == this.MasterColumns ) + if( ( m_masterColumnManager != null ) && ( sender == m_masterColumnManager.Columns ) ) { - Debug.Assert( sender != null ); - this.OnMasterColumnsPropertyChanged( ( PropertyChangedEventArgs )e ); } - else if( sender == this.DetailConfiguration ) + else if( sender == m_detailConfiguration ) { - Debug.Assert( sender != null ); - this.OnDetailConfigurationPropertyChanged( ( PropertyChangedEventArgs )e ); } - - return true; } - else if( managerType == typeof( VisibleColumnsUpdatedEventManager ) ) + else if( managerType == typeof( ColumnsLayoutChangedEventManager ) ) { - if( sender == this.MasterColumns ) + if( sender == m_masterColumnManager ) { - Debug.Assert( sender != null ); - this.OnMasterVisibleColumnsUpdated( e ); } - else if( sender == this.DetailColumns ) + else if( sender == m_detailColumnManager ) { - Debug.Assert( sender != null ); - this.OnDetailVisibleColumnsUpdated( e ); } - - return true; + } + else if( managerType == typeof( MappingChangedEventManager ) ) + { + if( sender == m_itemPropertyMap ) + { + this.OnItemPropertyMapMappingChanged( e ); + } } else if( managerType == typeof( ViewChangedEventManager ) ) { - if( sender == this.DataGridControl ) + if( sender == m_dataGridControl ) { - Debug.Assert( sender != null ); - this.OnViewChanged(); } - - return true; + } + else + { + return false; } - return false; + return true; } #endregion - #region DeferSynchronizationHelper Private Class + private readonly DetailConfiguration m_detailConfiguration; + private readonly DataGridItemPropertyMap m_itemPropertyMap; + private readonly Dictionary m_pairedColumns = new Dictionary( 0 ); - private sealed class DeferSynchronizationHelper : IDisposable - { - internal DeferSynchronizationHelper( ColumnSynchronizationManager owner ) - { - if( owner == null ) - throw new ArgumentNullException( "owner" ); + private bool m_isUpdatingColumns; - m_owner = owner; + #region DeferState Private Class - Interlocked.Increment( ref owner.m_deferSynchronizationCount ); + private sealed class DeferState : DeferredDisposableState + { + internal DeferState( ColumnSynchronizationManager target ) + { + Debug.Assert( target != null ); + m_target = target; } - void IDisposable.Dispose() + protected override bool IsDeferred { - this.Dispose( true ); - GC.SuppressFinalize( this ); + get + { + return m_target.IsSynchronizationDeferred; + } } - private void Dispose( bool disposing ) + protected override void Increment() { - Debug.Assert( disposing ); - - var owner = m_owner; - if( Interlocked.CompareExchange( ref m_owner, null, owner ) == null ) - return; - - if( Interlocked.Decrement( ref owner.m_deferSynchronizationCount ) != 0 ) - return; - - owner.UpdateColumns(); + m_target.m_deferSynchronizationCount++; } - ~DeferSynchronizationHelper() + protected override void Decrement() { - this.Dispose( false ); + m_target.m_deferSynchronizationCount--; } - #region Private Fields - - private ColumnSynchronizationManager m_owner; + protected override void OnDeferEnded( bool disposing ) + { + m_target.UpdateColumns(); + } - #endregion + private readonly ColumnSynchronizationManager m_target; } #endregion @@ -733,14 +620,32 @@ namespace Xceed.Wpf.DataGrid private abstract class SynchronizationEntry { - protected SynchronizationEntry( SynchronizationKey key ) + protected SynchronizationEntry( ColumnSynchronizationManager owner, SynchronizationKey key ) { + if( owner == null ) + throw new ArgumentNullException( "owner" ); + if( key == null ) throw new ArgumentNullException( "key" ); + m_owner = owner; m_key = key; } + #region Owner Protected Property + + protected ColumnSynchronizationManager Owner + { + get + { + return m_owner; + } + } + + private readonly ColumnSynchronizationManager m_owner; + + #endregion + #region MasterColumn Protected Property protected ColumnBase MasterColumn @@ -801,201 +706,334 @@ namespace Xceed.Wpf.DataGrid private sealed class BoundColumn : SynchronizationEntry { - internal BoundColumn( SynchronizationKey key ) - : base( key ) + internal BoundColumn( ColumnSynchronizationManager owner, SynchronizationKey key ) + : base( owner, key ) { if( key.MasterColumn == null ) throw new ArgumentException( "The master column is not set.", "key" ); - - m_bindings = BoundColumn.CreateBindings( key.MasterColumn ).ToArray(); } - #region IsListeningEvents Private Property - - private bool IsListeningEvents + public override void Synchronize() { - get - { - return m_isListeningEvents; - } - set + var masterColumn = this.MasterColumn; + var detailColumn = this.DetailColumn; + + if( m_localValues == null ) { - m_isListeningEvents = value; + m_localValues = new Dictionary( 8 ); + + masterColumn.PropertyChanged += new PropertyChangedEventHandler( this.OnMasterColumnPropertyChanged ); + masterColumn.FittedWidthRequested += new FittedWidthRequestedEventHandler( this.OnMasterColumnFittedWidthRequested ); + + BoundColumn.StoreLocalValue( m_localValues, detailColumn, ColumnBase.WidthProperty ); + BoundColumn.StoreLocalValue( m_localValues, detailColumn, ColumnBase.MinWidthProperty ); + BoundColumn.StoreLocalValue( m_localValues, detailColumn, ColumnBase.MaxWidthProperty ); + BoundColumn.StoreLocalValue( m_localValues, detailColumn, ColumnBase.DesiredWidthProperty ); + BoundColumn.StoreLocalValue( m_localValues, detailColumn, ColumnBase.VisibleProperty ); + BoundColumn.StoreLocalValue( m_localValues, detailColumn, ColumnReorderingDragSourceManager.AnimatedColumnReorderingTranslationProperty ); + BoundColumn.StoreLocalValue( m_localValues, detailColumn, TableflowView.IsBeingDraggedAnimatedProperty ); + BoundColumn.StoreLocalValue( m_localValues, detailColumn, TableflowView.ColumnReorderingDragSourceManagerProperty ); } - } - private bool m_isListeningEvents; //false + BoundColumn.SetValue( masterColumn, detailColumn, ColumnBase.WidthProperty ); + BoundColumn.SetValue( masterColumn, detailColumn, ColumnBase.MinWidthProperty ); + BoundColumn.SetValue( masterColumn, detailColumn, ColumnBase.MaxWidthProperty ); + BoundColumn.SetValue( masterColumn, detailColumn, ColumnBase.DesiredWidthProperty ); + BoundColumn.SetValue( masterColumn, detailColumn, ColumnBase.VisibleProperty ); + BoundColumn.SetValue( masterColumn, detailColumn, ColumnReorderingDragSourceManager.AnimatedColumnReorderingTranslationProperty ); + BoundColumn.SetValue( masterColumn, detailColumn, TableflowView.IsBeingDraggedAnimatedProperty ); + BoundColumn.SetValue( masterColumn, detailColumn, TableflowView.ColumnReorderingDragSourceManagerProperty ); - #endregion + this.UpdateTargetPosition(); + } - public override void Synchronize() + public override void Desynchronize() { - this.SubscribeEvents(); + if( m_localValues == null ) + return; - var targetColumn = this.DetailColumn; + var localValues = m_localValues; + m_localValues = null; - foreach( var entry in m_bindings ) - { - var dp = entry.Key; - var binding = entry.Value; + var masterColumn = this.MasterColumn; + masterColumn.PropertyChanged -= new PropertyChangedEventHandler( this.OnMasterColumnPropertyChanged ); + masterColumn.FittedWidthRequested -= new FittedWidthRequestedEventHandler( this.OnMasterColumnFittedWidthRequested ); + + var detailColumn = this.DetailColumn; + BoundColumn.RestoreLocalValue( localValues, detailColumn, ColumnBase.WidthProperty ); + BoundColumn.RestoreLocalValue( localValues, detailColumn, ColumnBase.MinWidthProperty ); + BoundColumn.RestoreLocalValue( localValues, detailColumn, ColumnBase.MaxWidthProperty ); + BoundColumn.RestoreLocalValue( localValues, detailColumn, ColumnBase.DesiredWidthProperty ); + BoundColumn.RestoreLocalValue( localValues, detailColumn, ColumnBase.VisibleProperty ); + BoundColumn.RestoreLocalValue( localValues, detailColumn, ColumnReorderingDragSourceManager.AnimatedColumnReorderingTranslationProperty ); + BoundColumn.RestoreLocalValue( localValues, detailColumn, TableflowView.IsBeingDraggedAnimatedProperty ); + BoundColumn.RestoreLocalValue( localValues, detailColumn, TableflowView.ColumnReorderingDragSourceManagerProperty ); + + detailColumn.ClearValue( ColumnBase.VisiblePositionProperty ); + } - // The appropriate binding is still in place. - var currentBinding = BindingOperations.GetBindingBase( targetColumn, dp ); - if( currentBinding == binding ) - continue; + private static void StoreLocalValue( Dictionary store, ColumnBase column, DependencyProperty property ) + { + Debug.Assert( store != null ); + Debug.Assert( column != null ); + Debug.Assert( property != null ); - if( currentBinding != null ) + var binding = BindingOperations.GetBindingBase( column, property ); + if( binding != null ) + { + store[ property ] = binding; + } + else + { + var value = column.ReadLocalValue( property ); + if( value != DependencyProperty.UnsetValue ) { - m_localValues[ dp ] = currentBinding; + store[ property ] = value; } else { - var localValue = targetColumn.ReadLocalValue( dp ); - if( localValue != DependencyProperty.UnsetValue ) - { - m_localValues[ dp ] = localValue; - } - else - { - m_localValues.Remove( dp ); - } + store.Remove( property ); } - - BindingOperations.SetBinding( targetColumn, dp, binding ); } + } - var visiblePosition = this.GetTargetVisiblePosition(); - if( visiblePosition.HasValue ) + private static void RestoreLocalValue( Dictionary store, ColumnBase column, DependencyProperty property ) + { + Debug.Assert( store != null ); + Debug.Assert( column != null ); + Debug.Assert( property != null ); + + object value; + if( !store.TryGetValue( property, out value ) || ( value == DependencyProperty.UnsetValue ) ) + { + column.ClearValue( property ); + } + else if( value is BindingBase ) { - targetColumn.VisiblePosition = visiblePosition.Value; + BindingOperations.SetBinding( column, property, ( BindingBase )value ); } else { - targetColumn.ClearValue( ColumnBase.VisiblePositionProperty ); + column.SetValue( property, value ); } } - public override void Desynchronize() + private static void SetValue( ColumnBase source, ColumnBase destination, DependencyProperty property, string propertyName ) { - this.UnsubscribeEvents(); - - var targetColumn = this.DetailColumn; + Debug.Assert( property != null ); - foreach( var entry in m_bindings ) + if( string.IsNullOrEmpty( propertyName ) || ( propertyName == property.Name ) ) { - var dp = entry.Key; - var binding = entry.Value; + BoundColumn.SetValue( source, destination, property ); + } + } - // The appropriate binding is still in place. - var currentBinding = BindingOperations.GetBindingBase( targetColumn, dp ); - if( currentBinding == binding ) - { - object oldValue; + private static void SetValue( ColumnBase source, ColumnBase destination, DependencyProperty property ) + { + Debug.Assert( source != null ); + Debug.Assert( destination != null ); + Debug.Assert( property != null ); + + destination.SetValue( property, source.GetValue( property ) ); + } + + private void UpdateTargetPosition() + { + var detailConfig = this.DetailConfiguration; + var dataGridControl = detailConfig.DataGridControl; + + if( dataGridControl == null ) + return; + + var masterColumn = this.MasterColumn; + var masterColumnManager = DataGridControl.GetDataGridContext( dataGridControl ).ColumnManager; + var masterColumnLocation = masterColumnManager.GetColumnLocationFor( masterColumn ); + + if( masterColumnLocation == null ) + return; + + var detailColumn = this.DetailColumn; + var detailColumnManager = detailConfig.ColumnManager; + var detailColumnLocation = detailColumnManager.GetColumnLocationFor( detailColumn ); + + if( detailColumnLocation == null ) + return; - if( m_localValues.TryGetValue( dp, out oldValue ) ) + var map = detailConfig.ItemPropertyMap; + var previousMasterLocation = masterColumnLocation.GetPreviousSiblingOrCousin(); + Debug.Assert( previousMasterLocation != null ); + + switch( previousMasterLocation.Type ) + { + case LocationType.Start: + case LocationType.Splitter: { - var oldBinding = oldValue as BindingBase; - if( oldBinding != null ) - { - BindingOperations.SetBinding( targetColumn, dp, oldBinding ); - } - else + for( var previousDetailLocation = detailColumnLocation.GetPreviousSiblingOrCousin(); previousDetailLocation != null; previousDetailLocation = previousDetailLocation.GetPreviousSiblingOrCousin() ) { - targetColumn.SetValue( dp, oldValue ); + // The detail column is at the appropriate location. + if( previousDetailLocation.Type == previousMasterLocation.Type ) + return; + + if( previousDetailLocation.Type != LocationType.Column ) + break; + + ColumnBase unused; + if( DataGridItemPropertyMapHelper.TryGetMasterColumn( map, masterColumnManager.Columns, ( ( ColumnHierarchyManager.IColumnLocation )previousDetailLocation ).Column, out unused ) ) + break; } } - else + break; + + case LocationType.Column: { - BindingOperations.ClearBinding( targetColumn, dp ); + var previousMasterColumn = ( ( ColumnHierarchyManager.IColumnLocation )previousMasterLocation ).Column; + + for( var previousDetailLocation = detailColumnLocation.GetPreviousSiblingOrCousin(); previousDetailLocation != null; previousDetailLocation = previousDetailLocation.GetPreviousSiblingOrCousin() ) + { + if( previousDetailLocation.Type != LocationType.Column ) + break; + + ColumnBase targetMasterColumn; + if( DataGridItemPropertyMapHelper.TryGetMasterColumn( map, masterColumnManager.Columns, ( ( ColumnHierarchyManager.IColumnLocation )previousDetailLocation ).Column, out targetMasterColumn ) ) + { + // The detail column is at the appropriate location. + if( previousMasterColumn == targetMasterColumn ) + return; + } + } } - } + break; - m_localValues.Remove( dp ); + default: + // Unexpected location. + throw new NotSupportedException(); } - targetColumn.ClearValue( ColumnBase.VisiblePositionProperty ); - } + var nextMasterLocation = masterColumnLocation.GetNextSiblingOrCousin(); + Debug.Assert( nextMasterLocation != null ); - private static IEnumerable> CreateBindings( ColumnBase source ) - { - yield return BoundColumn.CreateBinding( ColumnBase.WidthProperty, source ); - yield return BoundColumn.CreateBinding( ColumnBase.MinWidthProperty, source ); - yield return BoundColumn.CreateBinding( ColumnBase.MaxWidthProperty, source ); - yield return BoundColumn.CreateBinding( ColumnBase.DesiredWidthProperty, source ); - yield return BoundColumn.CreateBinding( ColumnBase.VisibleProperty, source ); - yield return BoundColumn.CreateBinding( ColumnReorderingDragSourceManager.AnimatedColumnReorderingTranslationProperty, source ); - yield return BoundColumn.CreateBinding( TableflowView.IsBeingDraggedAnimatedProperty, source ); - yield return BoundColumn.CreateBinding( TableflowView.ColumnReorderingDragSourceManagerProperty, source ); - } + switch( nextMasterLocation.Type ) + { + case LocationType.Splitter: + case LocationType.Orphan: + { + for( var nextDetailLocation = detailColumnLocation.GetNextSiblingOrCousin(); nextDetailLocation != null; nextDetailLocation = nextDetailLocation.GetNextSiblingOrCousin() ) + { + // The detail column is at the appropriate location. + if( nextDetailLocation.Type == nextMasterLocation.Type ) + return; - private static KeyValuePair CreateBinding( DependencyProperty dp, ColumnBase source ) - { - if( dp == null ) - throw new ArgumentNullException( "property" ); + if( nextDetailLocation.Type != LocationType.Column ) + break; - if( source == null ) - throw new ArgumentNullException( "source" ); + ColumnBase unused; + if( DataGridItemPropertyMapHelper.TryGetMasterColumn( map, masterColumnManager.Columns, ( ( ColumnHierarchyManager.IColumnLocation )nextDetailLocation ).Column, out unused ) ) + break; + } + } + break; - var binding = new Binding(); - binding.Path = new PropertyPath( dp ); - binding.Source = source; + case LocationType.Column: + { + var nextMasterColumn = ( ( ColumnHierarchyManager.IColumnLocation )nextMasterLocation ).Column; - return new KeyValuePair( dp, binding ); - } + for( var nextDetailLocation = detailColumnLocation.GetNextSiblingOrCousin(); nextDetailLocation != null; nextDetailLocation = nextDetailLocation.GetNextSiblingOrCousin() ) + { + if( nextDetailLocation.Type != LocationType.Column ) + break; + + ColumnBase targetMasterColumn; + if( DataGridItemPropertyMapHelper.TryGetMasterColumn( map, masterColumnManager.Columns, ( ( ColumnHierarchyManager.IColumnLocation )nextDetailLocation ).Column, out targetMasterColumn ) ) + { + // The detail column is at the appropriate location. + if( nextMasterColumn == targetMasterColumn ) + return; + } + } + } + break; - private Nullable GetTargetVisiblePosition() - { - var detailConfig = this.DetailConfiguration; + default: + // Unexpected location. + throw new NotSupportedException(); + } - var dataGridControl = detailConfig.DataGridControl; - if( dataGridControl == null ) - return null; + // If we get here, it means that the column is really not at the appropriate location. + for( var pivotMasterLocation = previousMasterLocation; pivotMasterLocation != null; pivotMasterLocation = pivotMasterLocation.GetPreviousSiblingOrCousin() ) + { + if( pivotMasterLocation.Type == LocationType.Column ) + { + ColumnBase pivotDetailColumn; + if( !DataGridItemPropertyMapHelper.TryGetDetailColumn( map, detailColumnManager.Columns, ( ( ColumnHierarchyManager.IColumnLocation )pivotMasterLocation ).Column, out pivotDetailColumn ) ) + continue; - var masterColumn = this.MasterColumn; - int visiblePosition = masterColumn.VisiblePosition; - if( visiblePosition < 0 ) - return null; + var pivotDetailLocation = ( pivotDetailColumn != null ) ? detailColumnManager.GetColumnLocationFor( pivotDetailColumn ) : null; + if( pivotDetailLocation == null ) + continue; - var masterColumnNode = dataGridControl.ColumnsByVisiblePosition.Find( masterColumn ); - if( masterColumnNode == null ) - return null; + Debug.Assert( detailColumnLocation.CanMoveAfter( pivotDetailLocation ) ); + detailColumnLocation.MoveAfter( pivotDetailLocation ); + } + else + { + switch( pivotMasterLocation.Type ) + { + case LocationType.Start: + { + var pivotDetailLocation = detailColumnManager.GetLevelMarkersFor( detailColumnManager.Columns ).Start; - var map = this.DetailConfiguration.ItemPropertyMap; + if( !detailColumnLocation.CanMoveAfter( pivotDetailLocation ) ) + throw new NotSupportedException(); - // Remove master columns that are not linked to a detail column from the VisiblePosition count. - masterColumnNode = masterColumnNode.Previous; - while( masterColumnNode != null ) - { - string detailColumnName; - if( !map.TryGetItemPropertyName( masterColumnNode.Value, out detailColumnName ) ) - { - visiblePosition--; - } + detailColumnLocation.MoveAfter( pivotDetailLocation ); + } + break; - masterColumnNode = masterColumnNode.Previous; - } + case LocationType.Splitter: + { + var pivotDetailLocation = detailColumnManager.GetLevelMarkersFor( detailColumnManager.Columns ).Splitter; + + if( !detailColumnLocation.CanMoveAfter( pivotDetailLocation ) ) + throw new NotSupportedException(); - Debug.Assert( visiblePosition >= 0 ); + detailColumnLocation.MoveAfter( pivotDetailLocation ); + } + break; + + default: + // Unexpected location. + throw new NotSupportedException(); + } + } - return visiblePosition; + // The detail column is now at the appropriate location. + return; + } } - private void SubscribeEvents() + private void OnMasterColumnPropertyChanged( object sender, PropertyChangedEventArgs e ) { - if( this.IsListeningEvents ) + var masterColumn = sender as ColumnBase; + if( masterColumn == null ) return; - this.MasterColumn.FittedWidthRequested += new FittedWidthRequestedEventHandler( this.OnMasterColumnFittedWidthRequested ); - this.IsListeningEvents = true; - } + Debug.Assert( masterColumn == this.MasterColumn ); - private void UnsubscribeEvents() - { - if( !this.IsListeningEvents ) + var masterColumnManager = this.Owner.MasterColumnManager; + if( ( masterColumnManager == null ) || masterColumnManager.IsUpdateDeferred ) return; - this.MasterColumn.FittedWidthRequested -= new FittedWidthRequestedEventHandler( this.OnMasterColumnFittedWidthRequested ); - this.IsListeningEvents = false; + var detailColumn = this.DetailColumn; + var propertyName = e.PropertyName; + + BoundColumn.SetValue( masterColumn, detailColumn, ColumnBase.WidthProperty, propertyName ); + BoundColumn.SetValue( masterColumn, detailColumn, ColumnBase.MinWidthProperty, propertyName ); + BoundColumn.SetValue( masterColumn, detailColumn, ColumnBase.MaxWidthProperty, propertyName ); + BoundColumn.SetValue( masterColumn, detailColumn, ColumnBase.DesiredWidthProperty, propertyName ); + BoundColumn.SetValue( masterColumn, detailColumn, ColumnBase.VisibleProperty, propertyName ); + BoundColumn.SetValue( masterColumn, detailColumn, ColumnReorderingDragSourceManager.AnimatedColumnReorderingTranslationProperty, propertyName ); + BoundColumn.SetValue( masterColumn, detailColumn, TableflowView.IsBeingDraggedAnimatedProperty, propertyName ); + BoundColumn.SetValue( masterColumn, detailColumn, TableflowView.ColumnReorderingDragSourceManagerProperty, propertyName ); } private void OnMasterColumnFittedWidthRequested( object sender, FittedWidthRequestedEventArgs e ) @@ -1009,12 +1047,7 @@ namespace Xceed.Wpf.DataGrid e.SetValue( fittedWidth ); } - #region Private Fields - - private readonly KeyValuePair[] m_bindings; - private readonly Dictionary m_localValues = new Dictionary( 0 ); - - #endregion + private Dictionary m_localValues; } #endregion @@ -1023,8 +1056,8 @@ namespace Xceed.Wpf.DataGrid private sealed class UnboundColumn : SynchronizationEntry { - internal UnboundColumn( SynchronizationKey key ) - : base( key ) + internal UnboundColumn( ColumnSynchronizationManager owner, SynchronizationKey key ) + : base( owner, key ) { if( key.MasterColumn != null ) throw new ArgumentException( "The master column should not be set.", "key" ); @@ -1085,11 +1118,7 @@ namespace Xceed.Wpf.DataGrid } } - #region Private Fields - private object m_localValue = DependencyProperty.UnsetValue; - - #endregion } #endregion diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Converters/EmptyStringToBooleanConverter.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Converters/EmptyStringToBooleanConverter.cs index ae57b643..65111d45 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Converters/EmptyStringToBooleanConverter.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Converters/EmptyStringToBooleanConverter.cs @@ -25,10 +25,7 @@ namespace Xceed.Wpf.DataGrid.Converters { public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) { - string strValue = value as string; - - // Not a mistake: returns true if *value* is null or *strValue* is "". - return ( value == null ) || ( strValue == string.Empty ); + return string.IsNullOrWhiteSpace( value as string ); } public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CurrencyManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CurrencyManager.cs index 6215e1ac..ea7925d2 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CurrencyManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/CurrencyManager.cs @@ -16,19 +16,17 @@ using System; using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; using System.Linq; -using System.Text; using System.Windows; using System.Windows.Data; -using System.ComponentModel; namespace Xceed.Wpf.DataGrid { - internal class CurrencyManager + internal sealed class CurrencyManager : IWeakEventListener { - #region CONSTRUCTORS - - public CurrencyManager( DataGridContext dataGridContext, CollectionView collectionView ) + internal CurrencyManager( DataGridContext dataGridContext, CollectionView collectionView ) { if( dataGridContext == null ) throw new ArgumentNullException( "dataGridContext" ); @@ -39,50 +37,12 @@ namespace Xceed.Wpf.DataGrid m_dataGridContext = dataGridContext; m_collectionView = collectionView; - System.Diagnostics.Debug.Assert( m_dataGridContext.CurrentItem == m_collectionView.CurrentItem ); + Debug.Assert( m_dataGridContext.CurrentItem == m_collectionView.CurrentItem ); this.RegisterListeners(); } - #endregion CONSTRUCTORS - - #region IsCurrentChanging Property - - public bool IsCurrentChanging - { - get; - private set; - } - - #endregion IsCurrentChanging Property - - #region PUBLIC METHODS - - public void CleanCurrencyManager() - { - this.UnregisterListeners(); - - m_dataGridContext = null; - m_collectionView = null; - } - - #endregion PUBLIC METHODS - - #region EVENT HANDLERS - - private void OnDataGridContextCurrentItemChanged( object sender, EventArgs e ) - { - this.ChangeCollectionViewCurrentItem(); - } - - private void OnCollectionViewCurrentChanged( object sender, EventArgs e ) - { - this.ChangeDataGridContextCurrentItem(); - } - - #endregion EVENT HANDLERS - - #region PRIVATE PROPERTIES + #region IsSetCurrentInProgress Private Property private bool IsSetCurrentInProgress { @@ -92,6 +52,10 @@ namespace Xceed.Wpf.DataGrid } } + #endregion + + #region ShouldSynchronizeCurrentItem Private Property + private bool ShouldSynchronizeCurrentItem { get @@ -100,34 +64,47 @@ namespace Xceed.Wpf.DataGrid } } + #endregion + + #region ShouldSynchronizeSelectionWithCurrent Private Property + private bool ShouldSynchronizeSelectionWithCurrent { get { + // #case 158670 + // When using DataGridVirtualizingCollectionViewBase, the synchronization between + // currentItem and Selection will only be done if currentItem is modified in code-behind. + var dgvcvb = m_collectionView.SourceCollection as DataGridVirtualizingCollectionViewBase; + if( ( dgvcvb != null ) && !dgvcvb.CanSynchronizeSelectionWithCurrent ) + return false; + return m_dataGridContext.DataGridControl.SynchronizeSelectionWithCurrent; } } #endregion - #region PRIVATE METHODS + internal void CleanManager() + { + this.UnregisterListeners(); + } private void ChangeCollectionViewCurrentItem() { - if( ( this.IsCurrentChanging ) || ( !this.ShouldSynchronizeCurrentItem ) ) + if( m_isCurrentChanging || !this.ShouldSynchronizeCurrentItem ) return; - this.IsCurrentChanging = true; + m_isCurrentChanging = true; try { - // Synchronize the CurrentItem of the CollecitonView - // with the one of the DataGridContext. + // Synchronize the CurrentItem of the CollecitonView with the one of the DataGridContext. m_collectionView.MoveCurrentToPosition( m_dataGridContext.CurrentItemIndex ); } finally { - this.IsCurrentChanging = false; + m_isCurrentChanging = false; } } @@ -137,10 +114,10 @@ namespace Xceed.Wpf.DataGrid if( this.IsSetCurrentInProgress ) return; - if( ( this.IsCurrentChanging ) || ( !this.ShouldSynchronizeCurrentItem ) ) + if( m_isCurrentChanging || !this.ShouldSynchronizeCurrentItem ) return; - this.IsCurrentChanging = true; + m_isCurrentChanging = true; try { @@ -157,12 +134,14 @@ namespace Xceed.Wpf.DataGrid AutoScrollCurrentItemSourceTriggers.CollectionViewCurrentItemChanged ); if( m_collectionView.CurrentItem == null ) + { this.ChangeCurrentDataGridContext(); + } } catch( DataGridException ) { - // When we deleted an item in edition that contain invalid data, we don't want a throw to go all the way up to the end user. - // We try to abort the edition in that case. + // When we deleted an item in edit that contain invalid data, we don't want a throw to go all the way up to the end user. + // We try to abort the edit in that case. if( ( m_dataGridContext.IsCurrent ) && ( m_dataGridContext.DataGridControl.IsBeingEdited ) && ( !m_dataGridContext.Items.Contains( m_dataGridContext.CurrentItem ) ) ) { @@ -179,97 +158,141 @@ namespace Xceed.Wpf.DataGrid AutoScrollCurrentItemSourceTriggers.CollectionViewCurrentItemChanged ); if( m_collectionView.CurrentItem == null ) + { this.ChangeCurrentDataGridContext(); + } } } finally { - this.IsCurrentChanging = false; + m_isCurrentChanging = false; } } private void ChangeCurrentDataGridContext() { - if( ( m_dataGridContext.ParentDataGridContext == null ) - || ( m_dataGridContext.ParentItem == null ) ) + var parentDataGridContext = m_dataGridContext.ParentDataGridContext; + var parentItem = m_dataGridContext.ParentItem; + + if( ( parentDataGridContext == null ) || ( parentItem == null ) ) return; - List childContexts = this.GetParentItemChildContexts(); - int currentContextIndex = childContexts.IndexOf( m_dataGridContext ); + var childContexts = CurrencyManager.GetChildContexts( parentDataGridContext, parentItem ).ToList(); if( childContexts.Count > 1 ) { - if( currentContextIndex < ( childContexts.Count - 1 ) ) + var currentContextIndex = childContexts.IndexOf( m_dataGridContext ); + int lookForwardFrom; + int lookBackwardFrom; + + if( currentContextIndex < 0 ) { - // We are not the last context, we'll search for a - // non-empty context after us. - for( int i = currentContextIndex + 1; i < childContexts.Count; i++ ) - { - DataGridContext childContext = childContexts[ i ]; + lookForwardFrom = 0; + lookBackwardFrom = -1; + } + else + { + lookForwardFrom = currentContextIndex + 1; + lookBackwardFrom = currentContextIndex - 1; + } - if( childContext.Items.Count == 0 ) - continue; + for( int i = lookForwardFrom; i < childContexts.Count; i++ ) + { + var childContext = childContexts[ i ]; + if( childContext.Items.Count <= 0 ) + continue; - childContext.SetCurrentItemCore( childContext.Items.GetItemAt( 0 ), false, this.ShouldSynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.CollectionViewCurrentItemChanged ); - return; - } + childContext.SetCurrentItemCore( childContext.Items.GetItemAt( 0 ), false, this.ShouldSynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.CollectionViewCurrentItemChanged ); + return; } - // No context have been found. We'll search for a - // non-empty context before us. - for( int i = currentContextIndex - 1; i >= 0; i-- ) + for( int i = lookBackwardFrom; i >= 0; i-- ) { - DataGridContext childContext = childContexts[ i ]; - - int count = childContext.Items.Count; + var childContext = childContexts[ i ]; - if( count == 0 ) + var itemsCount = childContext.Items.Count; + if( itemsCount <= 0 ) continue; - childContext.SetCurrentItemCore( childContext.Items.GetItemAt( count - 1 ), false, this.ShouldSynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.CollectionViewCurrentItemChanged ); + childContext.SetCurrentItemCore( childContext.Items.GetItemAt( itemsCount - 1 ), false, this.ShouldSynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.CollectionViewCurrentItemChanged ); return; } } // No context after or before us have been found, we will set the CurrentItem to our ParentItem. - m_dataGridContext.ParentDataGridContext.SetCurrentItemCore( m_dataGridContext.ParentItem, false, this.ShouldSynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.CollectionViewCurrentItemChanged ); - } - - private List GetParentItemChildContexts() - { - List childContexts = new List(); - - foreach( DetailConfiguration detailConfig in m_dataGridContext.ParentDataGridContext.DetailConfigurations ) - { - childContexts.Add( m_dataGridContext.ParentDataGridContext.GetChildContext( m_dataGridContext.ParentItem, detailConfig ) ); - } - - return childContexts; + parentDataGridContext.SetCurrentItemCore( parentItem, false, this.ShouldSynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.CollectionViewCurrentItemChanged ); } private void RegisterListeners() { // We are not checking this.ShouldSynchronizeCurrentItem since it might return the wrong value if the grid // is still in the process of being instantiated. - m_dataGridContext.CurrentItemChanged += new EventHandler( this.OnDataGridContextCurrentItemChanged ); - m_collectionView.CurrentChanged += new EventHandler( this.OnCollectionViewCurrentChanged ); + CurrentItemChangedEventManager.AddListener( m_dataGridContext, this ); + CurrentChangedEventManager.AddListener( m_collectionView, this ); } private void UnregisterListeners() { // We are not checking this.ShouldSynchronizeCurrentItem since it might have returned the wrong value // when RegisterListeners was called if the grid was still in the process of being instantiated. - m_dataGridContext.CurrentItemChanged -= new EventHandler( this.OnDataGridContextCurrentItemChanged ); - m_collectionView.CurrentChanged -= new EventHandler( this.OnCollectionViewCurrentChanged ); + CurrentItemChangedEventManager.RemoveListener( m_dataGridContext, this ); + CurrentChangedEventManager.RemoveListener( m_collectionView, this ); + } + + private static IEnumerable GetChildContexts( DataGridContext dataGridContext, object item ) + { + Debug.Assert( dataGridContext != null ); + Debug.Assert( item != null ); + + return ( from detailConfig in dataGridContext.DetailConfigurations + let childContext = dataGridContext.GetChildContext( item, detailConfig ) + where ( childContext != null ) + select childContext ); + } + + private void OnDataGridContextCurrentItemChanged( object sender, EventArgs e ) + { + Debug.Assert( sender == m_dataGridContext ); + + this.ChangeCollectionViewCurrentItem(); + } + + private void OnCollectionViewCurrentChanged( object sender, EventArgs e ) + { + Debug.Assert( sender == m_collectionView ); + + this.ChangeDataGridContextCurrentItem(); + } + + #region IWeakEventListener Members + + bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) + { + return this.OnReceiveWeakEvent( managerType, sender, e ); } - #endregion PRIVATE METHODS + private bool OnReceiveWeakEvent( Type managerType, object sender, EventArgs e ) + { + if( managerType == typeof( CurrentItemChangedEventManager ) ) + { + this.OnDataGridContextCurrentItemChanged( sender, e ); + } + else if( managerType == typeof( CurrentChangedEventManager ) ) + { + this.OnCollectionViewCurrentChanged( sender, e ); + } + else + { + return false; + } - #region PRIVATE FIELDS + return true; + } - private DataGridContext m_dataGridContext; - private CollectionView m_collectionView; + #endregion - #endregion PRIVATE FIELDS + private readonly DataGridContext m_dataGridContext; + private readonly CollectionView m_collectionView; + private bool m_isCurrentChanging; } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataCell.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataCell.cs index 49232e2a..6d83fceb 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataCell.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataCell.cs @@ -17,13 +17,11 @@ using System; using System.ComponentModel; using System.Diagnostics; -using System.Globalization; using System.Windows; -using System.Windows.Controls; +using System.Windows.Automation.Peers; using System.Windows.Data; using System.Windows.Input; using System.Xml; -using Xceed.Wpf.DataGrid.Converters; namespace Xceed.Wpf.DataGrid { @@ -70,6 +68,7 @@ namespace Xceed.Wpf.DataGrid #endregion + protected override void OnMouseEnter( MouseEventArgs e ) { //If the current CellEditorDisplayConditions requires display when mouse is over the Cell @@ -118,16 +117,6 @@ namespace Xceed.Wpf.DataGrid //call the helper function to setup the Cell's binding. this.SetupDisplayMemberBinding( dataGridContext ); } - else - { - - BindingExpression binding = BindingOperations.GetBindingExpression( this, DataCell.ContentProperty ); - - if( binding != null ) - { - binding.UpdateTarget(); - } - } } protected internal override void PrepareContainer( DataGridContext dataGridContext, object item ) @@ -154,34 +143,32 @@ namespace Xceed.Wpf.DataGrid protected internal virtual void SetupDisplayMemberBinding( DataGridContext dataGridContext ) { // Bind the cell content. - Column column = this.ParentColumn as Column; + var column = this.ParentColumn as Column; if( column != null ) { - BindingBase displayMemberBinding = null; - object dataContext = this.ParentRow.DataContext; + var displayMemberBinding = default( BindingBase ); + var dataItem = this.ParentRow.DataContext; // If the dataContext is our ParentRow, we do not create any binding - if( dataContext != this.ParentRow ) + if( dataItem != this.ParentRow ) { displayMemberBinding = column.GetDisplayMemberBinding(); if( displayMemberBinding == null ) { - if( ( dataGridContext == null ) || ( dataGridContext.ItemsSourceFieldDescriptors == null ) ) + if( dataGridContext == null ) throw new InvalidOperationException( "An attempt was made to create a DisplayMemberBinding before the DataGridContext has been initialized." ); if( !DesignerProperties.GetIsInDesignMode( this ) ) { - bool isDataGridUnboundItemProperty; + var propertyDescription = ItemsSourceHelper.CreateOrGetPropertyDescriptionFromColumn( dataGridContext, column, ( dataItem != null ) ? dataItem.GetType() : null ); + ItemsSourceHelper.UpdateColumnFromPropertyDescription( column, dataGridContext.DataGridControl.DefaultCellEditors, dataGridContext.AutoCreateForeignKeyConfigurations, propertyDescription ); - displayMemberBinding = ItemsSourceHelper.AutoCreateDisplayMemberBinding( column, dataGridContext, dataContext, out isDataGridUnboundItemProperty ); - - column.IsBoundToDataGridUnboundItemProperty = isDataGridUnboundItemProperty; + displayMemberBinding = column.GetDisplayMemberBinding(); } column.IsBindingAutoCreated = true; - column.SetDisplayMemberBinding( displayMemberBinding ); } } @@ -191,9 +178,7 @@ namespace Xceed.Wpf.DataGrid BindingOperations.SetBinding( this, Cell.ContentProperty, displayMemberBinding ); - XmlElement xmlElement = - this.GetValue( Cell.ContentProperty ) as XmlElement; - + var xmlElement = this.GetValue( Cell.ContentProperty ) as XmlElement; if( xmlElement != null ) { @@ -204,10 +189,9 @@ namespace Xceed.Wpf.DataGrid //under any circumstances, a cell that is bound to XML cannot be recycled m_canBeRecycled = false; - BindingOperations.ClearBinding( this, Cell.ContentProperty ); - this.ClearValue( Cell.ContentProperty ); + this.ClearDisplayMemberBinding(); - Binding xmlElementBinding = new Binding( "InnerXml" ); + var xmlElementBinding = new Binding( "InnerXml" ); xmlElementBinding.Source = xmlElement; xmlElementBinding.Mode = BindingMode.TwoWay; xmlElementBinding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit; @@ -215,12 +199,27 @@ namespace Xceed.Wpf.DataGrid BindingOperations.SetBinding( this, Cell.ContentProperty, xmlElementBinding ); } } + else + { + this.ClearDisplayMemberBinding(); + } + } + else + { + this.ClearDisplayMemberBinding(); } } internal virtual void ClearDisplayMemberBinding() { - BindingOperations.ClearBinding( this, Cell.ContentProperty ); + if( BindingOperations.IsDataBound( this, Cell.ContentProperty ) ) + { + BindingOperations.ClearBinding( this, Cell.ContentProperty ); + } + else + { + this.ClearValue( Cell.ContentProperty ); + } } internal override void ContentCommitted() @@ -239,9 +238,8 @@ namespace Xceed.Wpf.DataGrid if( column == null ) return null; - // If a foreignKey CellContentTemplate was found by the configuration, - // it must be used even if a CellContentTemplate is defined because the - // CellContentTemplate will be used by this template + // If a foreignKey CellContentTemplate was found by the configuration, it must be used even if a CellContentTemplate is defined + // because the CellContentTemplate will be used by this template var configuration = column.ForeignKeyConfiguration; if( configuration == null ) return null; @@ -251,8 +249,8 @@ namespace Xceed.Wpf.DataGrid internal override DataTemplate GetCellStringFormatDataTemplate( DataTemplate contentTemplate ) { + // parentColumn is verified to be not null in the calling method var parentColumn = this.ParentColumn; - Debug.Assert( parentColumn != null ); var format = parentColumn.CellContentStringFormat; Debug.Assert( !string.IsNullOrEmpty( format ) ); diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridBindingInfo.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridBindingInfo.cs index c35222d2..becf2ff1 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridBindingInfo.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridBindingInfo.cs @@ -31,8 +31,6 @@ namespace Xceed.Wpf.DataGrid { public class DataGridBindingInfo { - #region CONSTRUCTORS - public DataGridBindingInfo() { m_binding = new Binding(); @@ -48,8 +46,6 @@ namespace Xceed.Wpf.DataGrid m_binding.NotifyOnValidationError = true; } - #endregion CONSTRUCTORS - #region BindsDirectlyToSource Property public bool BindsDirectlyToSource @@ -273,19 +269,11 @@ namespace Xceed.Wpf.DataGrid #endregion Path Property - #region INTERNAL METHODS - internal Binding GetBinding() { return m_binding; } - #endregion INTERNAL METHODS - - #region PRIVATE FIELDS - private Binding m_binding; - - #endregion PRIVATE FIELDS } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridContext.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridContext.cs index 0914c69f..ab48b471 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridContext.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridContext.cs @@ -31,8 +31,6 @@ using System.Windows.Controls.Primitives; using System.Windows.Data; using System.Windows.Media; using Xceed.Utils.Collections; -using Xceed.Wpf.DataGrid.Automation; -using Xceed.Wpf.DataGrid.Utils; using Xceed.Wpf.DataGrid.Views; namespace Xceed.Wpf.DataGrid @@ -89,9 +87,23 @@ namespace Xceed.Wpf.DataGrid } //If the detailConfiguration is null then we are in the master... - if( detailConfiguration == null ) + if( m_detailConfig == null ) { - this.CreateStandaloneCollections(); + var columns = new ColumnCollection( dataGridControl, null ); + + m_columnManager = new ColumnHierarchyManager( columns ); + m_itemsSourcePropertyDescriptions = dataGridControl.ItemsSourcePropertyDescriptions; + m_itemPropertyMap = dataGridControl.ItemPropertyMap; + m_groupLevelDescriptions = new GroupLevelDescriptionCollection(); + + //in this particular case, I need to create a SortDescriptionsSyncContext to ensure I will be able to synchronize access to the sort descriptions collection. + m_sortDescriptionsSyncContext = new SortDescriptionsSyncContext(); + + //Register to the Columns Collection's CollectionChanged event to manage the Removal of the CurrentColumn. + CollectionChangedEventManager.AddListener( m_columnManager.Columns, this ); + + // Register to the VisibleColumnsChanged to update, if need be, the columns desired width when column stretching is active and there's a column reordering. + CollectionChangedEventManager.AddListener( m_columnManager.VisibleColumns, this ); CollectionChangedEventManager.AddListener( m_items.SortDescriptions, this ); CollectionChangedEventManager.AddListener( m_items.GroupDescriptions, this ); @@ -101,18 +113,24 @@ namespace Xceed.Wpf.DataGrid MaxGroupLevelsChangedEventManager.AddListener( m_dataGridControl, this ); MaxSortLevelsChangedEventManager.AddListener( m_dataGridControl, this ); ItemsSourceChangeCompletedEventManager.AddListener( m_dataGridControl, this ); + + this.HookToItemPropertiesChanged(); } //Detail DataGridContext else { + m_detailConfig.AddDataGridContext( this ); + + m_columnManager = m_detailConfig.ColumnManager; + m_itemsSourcePropertyDescriptions = m_detailConfig.ItemsSourcePropertyDescriptions; + m_itemPropertyMap = m_detailConfig.ItemPropertyMap; + //only listen to the detail grid config current column changed if the detail grid config is synchronized. CurrentColumnChangedEventManager.AddListener( m_detailConfig, this ); GroupConfigurationSelectorChangedEventManager.AddListener( m_detailConfig, this ); AllowDetailToggleChangedEventManager.AddListener( m_detailConfig, this ); - VisibilityChangingEventManager.AddListener( m_detailConfig.Columns, this ); - // Register to the VisibleColumnsChanged to update, if need be, the columns desired width // when column stretching is active and there's a column reordering. CollectionChangedEventManager.AddListener( m_detailConfig.VisibleColumns, this ); @@ -120,19 +138,20 @@ namespace Xceed.Wpf.DataGrid MaxGroupLevelsChangedEventManager.AddListener( m_detailConfig, this ); MaxSortLevelsChangedEventManager.AddListener( m_detailConfig, this ); - m_detailConfig.RequestingDelayBringIntoViewAndFocusCurrent += this.OnDetailConfigRequestingDelayBringIntoViewAndFocusCurrent; m_detailConfig.DetailConfigurations.DataGridControl = dataGridControl; } - CollectionChangedEventManager.AddListener( this.DetailConfigurations, this ); - VisibleColumnsUpdatedEventManager.AddListener( this.Columns, this ); - VisibleColumnsUpdatingEventManager.AddListener( this.Columns, this ); - RealizedContainersRequestedEventManager.AddListener( this.Columns, this ); - DistinctValuesRequestedEventManager.AddListener( this.Columns, this ); + Debug.Assert( m_columnManager != null ); + Debug.Assert( m_itemsSourcePropertyDescriptions != null ); + Debug.Assert( m_itemPropertyMap != null ); + ColumnsLayoutChangingEventManager.AddListener( m_columnManager, this ); + ColumnsLayoutChangedEventManager.AddListener( m_columnManager, this ); DetailVisibilityChangedEventManager.AddListener( this.DetailConfigurations, this ); + RealizedContainersRequestedEventManager.AddListener( this.Columns, this ); + DistinctValuesRequestedEventManager.AddListener( this.Columns, this ); - this.SetupViewProperties( true ); + this.SetupViewProperties(); this.InitializeViewProperties(); ViewChangedEventManager.AddListener( m_dataGridControl, this ); @@ -151,8 +170,6 @@ namespace Xceed.Wpf.DataGrid this.DetailLevel++; tempDataGridContext = tempDataGridContext.ParentDataGridContext; } - - this.HookToItemPropertiesChanged(); } private void Items_CollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) @@ -179,36 +196,25 @@ namespace Xceed.Wpf.DataGrid m_dataGridControl.CoerceValue( DataGridControl.SelectedItemProperty ); } - if( this.Peer != null ) - { - m_dataGridControl.QueueDataGridContextPeerChlidrenRefresh( this ); - } - m_dataGridControl.SelectionChangerManager.UpdateSelectionAfterSourceCollectionChanged( this, e ); + } internal void CleanDataGridContext() { - if( m_currencyManager != null ) - { - m_currencyManager.CleanCurrencyManager(); - m_currencyManager = null; - } + m_currencyManager.CleanManager(); if( m_items != null ) { CollectionChangedEventManager.RemoveListener( m_items, this ); - DataGridCollectionViewBase dataGridCollectionViewBase = this.ItemsSourceCollection as DataGridCollectionViewBase; - + var dataGridCollectionViewBase = this.ItemsSourceCollection as DataGridCollectionViewBase; if( dataGridCollectionViewBase != null ) { - dataGridCollectionViewBase.UnregisterChangedEvents(); - dataGridCollectionViewBase.RemoveSourceChangedListenersForDetail(); + dataGridCollectionViewBase.Dispose(); } } - //For non-master DataGridContext if( m_detailConfig == null ) { GroupConfigurationSelectorChangedEventManager.RemoveListener( m_dataGridControl, this ); @@ -219,6 +225,8 @@ namespace Xceed.Wpf.DataGrid CollectionChangedEventManager.RemoveListener( m_items.SortDescriptions, this ); CollectionChangedEventManager.RemoveListener( m_items.GroupDescriptions, this ); + + this.UnhookToItemPropertiesChanged( m_dataGridControlItemsSource as DataGridCollectionViewBase ); } else { @@ -229,24 +237,21 @@ namespace Xceed.Wpf.DataGrid MaxGroupLevelsChangedEventManager.RemoveListener( m_detailConfig, this ); MaxSortLevelsChangedEventManager.RemoveListener( m_detailConfig, this ); - m_detailConfig.RequestingDelayBringIntoViewAndFocusCurrent -= OnDetailConfigRequestingDelayBringIntoViewAndFocusCurrent; + m_detailConfig.RemoveDataGridContext( this ); } this.ClearSizeStates(); + ColumnsLayoutChangingEventManager.RemoveListener( m_columnManager, this ); + ColumnsLayoutChangedEventManager.RemoveListener( m_columnManager, this ); CollectionChangedEventManager.RemoveListener( this.DetailConfigurations, this ); - DetailVisibilityChangedEventManager.RemoveListener( this.DetailConfigurations, this ); - - VisibleColumnsUpdatedEventManager.RemoveListener( this.Columns, this ); - VisibleColumnsUpdatingEventManager.RemoveListener( this.Columns, this ); RealizedContainersRequestedEventManager.RemoveListener( this.Columns, this ); DistinctValuesRequestedEventManager.RemoveListener( this.Columns, this ); ViewChangedEventManager.RemoveListener( m_dataGridControl, this ); - this.UnhookToItemPropertiesChanged( m_dataGridControlItemsSource as DataGridCollectionViewBase ); - ColumnVirtualizationManager columnVirtualizationManager = this.ColumnVirtualizationManager; + var columnVirtualizationManager = this.ColumnVirtualizationManager; if( columnVirtualizationManager != null ) { columnVirtualizationManager.CleanManager(); @@ -280,8 +285,6 @@ namespace Xceed.Wpf.DataGrid #region ParentItem Read-Only Property - private object m_parentItem; - public object ParentItem { get @@ -290,7 +293,9 @@ namespace Xceed.Wpf.DataGrid } } - #endregion ParentItem Read-Only Property + private readonly object m_parentItem; + + #endregion #region AllowDetailToggle Property @@ -300,15 +305,11 @@ namespace Xceed.Wpf.DataGrid { if( m_detailConfig != null ) { - DefaultDetailConfiguration defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); + var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); if( defaultDetailConfig != null ) - { return defaultDetailConfig.AllowDetailToggle; - } - else - { - return m_detailConfig.AllowDetailToggle; - } + + return m_detailConfig.AllowDetailToggle; } return m_dataGridControl.AllowDetailToggle; @@ -323,13 +324,11 @@ namespace Xceed.Wpf.DataGrid { get { - DataGridCollectionViewBase dataGridCollectionViewBase = - this.ItemsSourceCollection as DataGridCollectionViewBase; - + var dataGridCollectionViewBase = this.ItemsSourceCollection as DataGridCollectionViewBase; if( dataGridCollectionViewBase == null ) return null; - return dataGridCollectionViewBase.DistinctValues; + return null; } } @@ -341,16 +340,10 @@ namespace Xceed.Wpf.DataGrid { get { - if( m_detailConfig != null ) - return m_detailConfig.Columns; - - return m_columns; + return m_columnManager.Columns; } } - private ColumnCollection m_columns; // = null, this variable will store the ColumnCollection only when - //the DataGridContext is used "desynchronized". - #endregion #region Items Property @@ -363,9 +356,9 @@ namespace Xceed.Wpf.DataGrid } } - private CollectionView m_items; + private readonly CollectionView m_items; - #endregion Items Property + #endregion #region OriginalItems Property @@ -465,7 +458,7 @@ namespace Xceed.Wpf.DataGrid this.SetCurrent( this.Items.GetItemAt( index ), null, index, this.CurrentColumn, false, isCancelable, synchronizeSelectionWithCurrent, trigger ); } - private void SetCurrentItemHelper( object dataItem, int sourceDataItemIndex ) + private void SetCurrentItem( object dataItem, int sourceDataItemIndex ) { // This is called only for DataItem if( ( m_currentItem == dataItem ) && ( m_currentItemIndex == sourceDataItemIndex ) ) @@ -480,14 +473,17 @@ namespace Xceed.Wpf.DataGrid private void OnCurrentItemChanged() { - if( this.CurrentItemChanged != null ) - this.CurrentItemChanged( this, EventArgs.Empty ); + var handler = this.CurrentItemChanged; + if( handler == null ) + return; + + handler.Invoke( this, EventArgs.Empty ); } private object m_currentItem; // = null private int m_currentItemIndex = -1; - #endregion CurrentItem + #endregion #region DefaultGroupConfiguration Read-Only Property @@ -497,15 +493,11 @@ namespace Xceed.Wpf.DataGrid { if( m_detailConfig != null ) { - DefaultDetailConfiguration defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); + var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); if( defaultDetailConfig != null ) - { return defaultDetailConfig.DefaultGroupConfiguration; - } - else - { - return m_detailConfig.DefaultGroupConfiguration; - } + + return m_detailConfig.DefaultGroupConfiguration; } return m_dataGridControl.DefaultGroupConfiguration; @@ -521,11 +513,9 @@ namespace Xceed.Wpf.DataGrid get { if( m_detailConfig != null ) - { return m_detailConfig.DetailConfigurations; - } - return m_dataGridControl.DetailConfigurations; + return null; } } @@ -539,18 +529,14 @@ namespace Xceed.Wpf.DataGrid { if( m_detailConfig != null ) { - DefaultDetailConfiguration defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); + var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); if( defaultDetailConfig != null ) - { return defaultDetailConfig.Footers; - } - else - { - return m_detailConfig.Footers; - } + + return m_detailConfig.Footers; } - Xceed.Wpf.DataGrid.Views.ViewBase view = m_dataGridControl.GetView( false ); + var view = m_dataGridControl.GetView(); if( view == null ) return new ObservableCollection(); @@ -573,8 +559,7 @@ namespace Xceed.Wpf.DataGrid } } - private GroupLevelDescriptionCollection m_groupLevelDescriptions; // = null, this variable will store the GroupLevelDescriptions only when - //the DataGridContext is used "desynchronized". + private readonly GroupLevelDescriptionCollection m_groupLevelDescriptions; //null #endregion @@ -586,29 +571,29 @@ namespace Xceed.Wpf.DataGrid { if( m_detailConfig != null ) { - DefaultDetailConfiguration defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); + var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); if( defaultDetailConfig != null ) - { return defaultDetailConfig.GroupConfigurationSelector; - } return m_detailConfig.GroupConfigurationSelector; } + return m_dataGridControl.GroupConfigurationSelector; } } private void OnGroupConfigurationSelectorChanged() { - if( this.GroupConfigurationSelectorChanged != null ) - { - this.GroupConfigurationSelectorChanged( this, EventArgs.Empty ); - } + var handler = this.GroupConfigurationSelectorChanged; + if( handler == null ) + return; + + handler.Invoke( this, EventArgs.Empty ); } internal event EventHandler GroupConfigurationSelectorChanged; - #endregion GroupConfigurationSelector Property + #endregion #region HasDetails Read-Only Property @@ -616,17 +601,6 @@ namespace Xceed.Wpf.DataGrid { get { - bool isDataGridCollectionView = ( this.ItemsSourceCollection is DataGridCollectionView ); - - if( !isDataGridCollectionView ) - return false; - - foreach( DetailConfiguration detailConfig in this.DetailConfigurations ) - { - if( detailConfig.Visible ) - return true; - } - return false; } } @@ -641,18 +615,14 @@ namespace Xceed.Wpf.DataGrid { if( m_detailConfig != null ) { - DefaultDetailConfiguration defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); + var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); if( defaultDetailConfig != null ) - { return defaultDetailConfig.Headers; - } - else - { - return m_detailConfig.Headers; - } + + return m_detailConfig.Headers; } - Xceed.Wpf.DataGrid.Views.ViewBase view = m_dataGridControl.GetView( false ); + var view = m_dataGridControl.GetView(); if( view == null ) return new ObservableCollection(); @@ -668,25 +638,13 @@ namespace Xceed.Wpf.DataGrid { get { - return IsCurrentCache; + return m_flags[ ( int )DataGridContextFlags.IsCurrent ]; } } - internal void SetIsCurrentHelper( bool value ) + internal void SetIsCurrent( bool value ) { - IsCurrentCache = value; - } - - private bool IsCurrentCache - { - get - { - return m_flags[ ( int )DataGridContextFlags.IsCurrent ]; - } - set - { - m_flags[ ( int )DataGridContextFlags.IsCurrent ] = value; - } + m_flags[ ( int )DataGridContextFlags.IsCurrent ] = value; } #endregion @@ -699,16 +657,13 @@ namespace Xceed.Wpf.DataGrid { if( m_detailConfig != null ) { - DefaultDetailConfiguration defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); + var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); if( defaultDetailConfig != null ) - { return defaultDetailConfig.ItemContainerStyle; - } - else - { - return m_detailConfig.ItemContainerStyle; - } + + return m_detailConfig.ItemContainerStyle; } + return m_dataGridControl.ItemContainerStyle; } } @@ -723,15 +678,11 @@ namespace Xceed.Wpf.DataGrid { if( m_detailConfig != null ) { - DefaultDetailConfiguration defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); + var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); if( defaultDetailConfig != null ) - { return defaultDetailConfig.ItemContainerStyleSelector; - } - else - { - return m_detailConfig.ItemContainerStyleSelector; - } + + return m_detailConfig.ItemContainerStyleSelector; } return m_dataGridControl.ItemContainerStyleSelector; @@ -764,9 +715,9 @@ namespace Xceed.Wpf.DataGrid } } - private SelectionItemCollection m_selectedItems; + private readonly SelectionItemCollection m_selectedItems; - #endregion SelectedItems Read-Only Property + #endregion #region SelectedItemRanges Read-Only Property @@ -778,9 +729,9 @@ namespace Xceed.Wpf.DataGrid } } - private SelectionItemRangeCollection m_selectedItemsRanges; + private readonly SelectionItemRangeCollection m_selectedItemsRanges; - #endregion SelectedItemRanges Read-Only Property + #endregion #region SelectedCellRanges Read-Only Property @@ -792,9 +743,9 @@ namespace Xceed.Wpf.DataGrid } } - private SelectionCellRangeCollection m_selectedCellRanges; + private readonly SelectionCellRangeCollection m_selectedCellRanges; - #endregion SelectedCellRanges Read-Only Property + #endregion #region SourceDetailConfiguration Read-Only Property @@ -808,7 +759,7 @@ namespace Xceed.Wpf.DataGrid private readonly DetailConfiguration m_detailConfig; - #endregion SourceDetailConfiguration Read-Only Property + #endregion #region VisibleColumns Read-Only Property @@ -816,16 +767,10 @@ namespace Xceed.Wpf.DataGrid { get { - if( m_detailConfig != null ) - return m_detailConfig.VisibleColumns; - - return m_visibleColumns; + return m_columnManager.VisibleColumns; } } - private ReadOnlyColumnCollection m_visibleColumns; // = null, this variable will store the VisibleColumns only when - //the DataGridContext is used "desynchronized". - #endregion #region AutoCreateForeignKeyConfigurations Internal Property @@ -835,9 +780,7 @@ namespace Xceed.Wpf.DataGrid get { if( m_detailConfig != null ) - { return m_detailConfig.AutoCreateForeignKeyConfigurations; - } return m_dataGridControl.AutoCreateForeignKeyConfigurations; } @@ -853,22 +796,18 @@ namespace Xceed.Wpf.DataGrid { if( m_detailConfig != null ) { - DefaultDetailConfiguration defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); + var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); if( defaultDetailConfig != null ) - { return defaultDetailConfig.MaxSortLevels; - } - else - { - return m_detailConfig.MaxSortLevels; - } + + return m_detailConfig.MaxSortLevels; } return m_dataGridControl.MaxSortLevels; } } - #endregion MaxSortLevels Property + #endregion #region MaxGroupLevels Property @@ -878,22 +817,18 @@ namespace Xceed.Wpf.DataGrid { if( m_detailConfig != null ) { - DefaultDetailConfiguration defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); + var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); if( defaultDetailConfig != null ) - { return defaultDetailConfig.MaxGroupLevels; - } - else - { - return m_detailConfig.MaxGroupLevels; - } + + return m_detailConfig.MaxGroupLevels; } return m_dataGridControl.MaxGroupLevels; } } - #endregion MaxGroupLevels Property + #endregion //--------- INTERNAL PROPERTIES --------- @@ -919,9 +854,9 @@ namespace Xceed.Wpf.DataGrid } } - private SelectedItemsStorage m_selectedItemsStore; + private readonly SelectedItemsStorage m_selectedItemsStore; - #endregion SelectedItemsStore Read-Only Property + #endregion #region SelectedItemsStore Read-Only Property @@ -933,9 +868,9 @@ namespace Xceed.Wpf.DataGrid } } - private SelectedCellsStorage m_selectedCellsStore; + private readonly SelectedCellsStorage m_selectedCellsStore; - #endregion SelectedItemsStore Read-Only Property + #endregion #region ColumnsByVisiblePosition Read-Only Property @@ -943,16 +878,10 @@ namespace Xceed.Wpf.DataGrid { get { - if( m_detailConfig != null ) - return m_detailConfig.ColumnsByVisiblePosition; - - return m_columnsByVisiblePosition; + return m_columnManager.ColumnsByVisiblePosition; } } - private HashedLinkedList m_columnsByVisiblePosition;// = null, this variable will store the ColumnsByVisiblePosition only when - //the DataGridContext is used "desynchronized". - #endregion #region ColumnStretchingManager Property @@ -962,7 +891,9 @@ namespace Xceed.Wpf.DataGrid get { if( m_columnStretchingManager == null ) + { m_columnStretchingManager = new ColumnStretchingManager( this ); + } return m_columnStretchingManager; } @@ -978,8 +909,7 @@ namespace Xceed.Wpf.DataGrid { get { - Row currentRow = this.CurrentRow; - + var currentRow = this.CurrentRow; if( currentRow == null ) return null; @@ -987,7 +917,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion CurrentCell Property + #endregion #region CurrentRow Read-Only Property @@ -1002,12 +932,10 @@ namespace Xceed.Wpf.DataGrid } } - #endregion CurrentRow Property + #endregion #region CustomItemContainerGenerator Read-Only Property - private CustomItemContainerGenerator m_generator; - internal CustomItemContainerGenerator CustomItemContainerGenerator { get @@ -1027,6 +955,8 @@ namespace Xceed.Wpf.DataGrid m_generator = generator; } + private CustomItemContainerGenerator m_generator; + #endregion #region InternalCurrentItem Read-Only Property @@ -1039,105 +969,40 @@ namespace Xceed.Wpf.DataGrid } } - internal void SetInternalCurrentItemHelper( object value ) + private void SetInternalCurrentItem( object value ) { m_internalCurrentItem = value; } - private object m_internalCurrentItem; // = null - - #endregion - - #region InternalCurrentItemNamesTree Read-Only Property - - internal object[] InternalCurrentItemNamesTree - { - get - { - return m_internalCurrentItemNamesTree; - } - } - - private void SetInternalCurrentItemNamesTree( object[] namesTree ) - { - m_internalCurrentItemNamesTree = namesTree; - } - - private object[] m_internalCurrentItemNamesTree; + private object m_internalCurrentItem; //null #endregion - #region ItemsSourceFieldDescriptors Property + #region ItemsSourcePropertyDescriptions Property - internal Dictionary ItemsSourceFieldDescriptors + internal PropertyDescriptionRouteDictionary ItemsSourcePropertyDescriptions { get { - if( m_detailConfig != null ) - { - Dictionary itemsSourceFieldDescriptors = m_detailConfig.ItemsSourceFieldDescriptors; - - if( itemsSourceFieldDescriptors == null ) - { - if( this.AreDetailsFlatten ) - { - var rootDataGridContext = this.RootDataGridContext; - Debug.Assert( ( rootDataGridContext != null ) && ( this != rootDataGridContext ) ); - - itemsSourceFieldDescriptors = ItemsSourceHelper.GetFields( rootDataGridContext.ItemsSourceFieldDescriptors, this.ItemPropertyMap, m_items, null ); - } - else - { - itemsSourceFieldDescriptors = ItemsSourceHelper.GetFields( m_items, null ); - } - - m_detailConfig.ItemsSourceFieldDescriptors = itemsSourceFieldDescriptors; - } - - return itemsSourceFieldDescriptors; - } - - //we are nescessarily in the master context in this case ( m_detailConfig == null ). - if( m_itemsSourceFieldDescriptors == null ) - m_itemsSourceFieldDescriptors = ItemsSourceHelper.GetFields( m_dataGridControl.ItemsSource, null ); - - return m_itemsSourceFieldDescriptors; - } - set - { - if( m_detailConfig != null ) - { - m_detailConfig.ItemsSourceFieldDescriptors = value; - return; - } - - m_itemsSourceFieldDescriptors = value; + return m_itemsSourcePropertyDescriptions; } } - private Dictionary m_itemsSourceFieldDescriptors; + private readonly PropertyDescriptionRouteDictionary m_itemsSourcePropertyDescriptions; #endregion #region ItemPropertyMap Internal Property - internal FieldNameMap ItemPropertyMap + internal DataGridItemPropertyMap ItemPropertyMap { get { - if( m_detailConfig != null ) - return m_detailConfig.ItemPropertyMap; - - if( m_itemPropertyMap == null ) - { - m_itemPropertyMap = new FieldNameMap(); - } - return m_itemPropertyMap; } } - private FieldNameMap m_itemPropertyMap; //null + private readonly DataGridItemPropertyMap m_itemPropertyMap; #endregion @@ -1210,9 +1075,7 @@ namespace Xceed.Wpf.DataGrid { get { - DataGridCollectionViewBase dataGridCollectionViewBase = - this.ItemsSourceCollection as DataGridCollectionViewBase; - + var dataGridCollectionViewBase = this.ItemsSourceCollection as DataGridCollectionViewBase; if( dataGridCollectionViewBase != null ) return dataGridCollectionViewBase.DataGridSortDescriptions.SyncContext; @@ -1221,7 +1084,7 @@ namespace Xceed.Wpf.DataGrid } } - private SortDescriptionsSyncContext m_sortDescriptionsSyncContext; // = null + private readonly SortDescriptionsSyncContext m_sortDescriptionsSyncContext; //null #endregion @@ -1232,13 +1095,12 @@ namespace Xceed.Wpf.DataGrid get { if( m_detailConfig != null ) - { return m_detailConfig.DefaultDetailConfiguration; - } return m_dataGridControl.DefaultDetailConfiguration; } } + #endregion #region ColumnVirtualizationManager Property @@ -1247,8 +1109,7 @@ namespace Xceed.Wpf.DataGrid { get { - ColumnVirtualizationManager columnVirtualizationManager = ColumnVirtualizationManager.GetColumnVirtualizationManager( this ); - + var columnVirtualizationManager = this.GetColumnVirtualizationManagerOrNull(); if( columnVirtualizationManager == null ) { columnVirtualizationManager = this.DataGridControl.GetView().CreateColumnVirtualizationManager( this ); @@ -1268,58 +1129,42 @@ namespace Xceed.Wpf.DataGrid #endregion - #region FixedHeaderFooterViewPortSize Property + #region ColumnManagerRowConfiguration Read-Only Internal Property - internal Size FixedHeaderFooterViewPortSize + internal ColumnManagerRowConfiguration ColumnManagerRowConfiguration { get { - return m_fixedHeaderFooterViewPortSize; - } - set - { - if( Size.Equals( m_fixedHeaderFooterViewPortSize, value ) == false ) - { - m_fixedHeaderFooterViewPortSize = value; - this.NotifyPropertyChanged( "FixedHeaderFooterViewPortSize" ); - } + if( m_detailConfig != null ) + return m_detailConfig.ColumnManagerRowConfiguration; + + return this.DataGridControl.ColumnManagerRowConfiguration; } } - private Size m_fixedHeaderFooterViewPortSize = new Size(); - #endregion - #region RecyclingManager Read-Only property + #region FixedHeaderFooterViewPortSize Property - internal RecyclingManager RecyclingManager + internal Size FixedHeaderFooterViewPortSize { get { - RecyclingManager retval = null; + return m_fixedHeaderFooterViewPortSize; + } + set + { + if( Size.Equals( value, m_fixedHeaderFooterViewPortSize ) ) + return; - //If the DataGridContext belongs to a detail, then use the DetailConfiguration's RecyclingManager - DetailConfiguration sourceDetailConfiguration = this.SourceDetailConfiguration; - if( sourceDetailConfiguration != null ) - { - retval = sourceDetailConfiguration.RecyclingManager; - } - else - { - //If the DataGridContext is from the Master context, then use and/or create the RecyclingManager - if( m_recyclingManager == null ) - { - m_recyclingManager = new RecyclingManager(); - } - retval = m_recyclingManager; - } + m_fixedHeaderFooterViewPortSize = value; - //RecyclingManager should never be null - Debug.Assert( retval != null ); - return retval; + this.OnPropertyChanged( "FixedHeaderFooterViewPortSize" ); } } + private Size m_fixedHeaderFooterViewPortSize = new Size(); + #endregion #region IsDeleteCommandEnabled Property @@ -1345,8 +1190,7 @@ namespace Xceed.Wpf.DataGrid return dataGridContext.DataGridControl.IsDeleteCommandEnabled; } - DefaultDetailConfiguration defaultDetailConfig = dataGridContext.GetDefaultDetailConfigurationForContext(); - + var defaultDetailConfig = dataGridContext.GetDefaultDetailConfigurationForContext(); if( defaultDetailConfig != null ) { if( defaultDetailConfig.ReadLocalValue( DefaultDetailConfiguration.IsDeleteCommandEnabledProperty ) != DependencyProperty.UnsetValue ) @@ -1361,7 +1205,7 @@ namespace Xceed.Wpf.DataGrid return this.FindIsDeletedCommandEnabledAmbient( dataGridContext.ParentDataGridContext ); } - #endregion IsDeleteCommandEnabled Property + #endregion #region SelectionChanged Event @@ -1380,20 +1224,6 @@ namespace Xceed.Wpf.DataGrid if( ( selectionInfo.RemovedItems.Count == 0 ) && ( selectionInfo.AddedItems.Count == 0 ) ) return; - if( ( AutomationPeer.ListenerExists( AutomationEvents.SelectionPatternOnInvalidated ) - || AutomationPeer.ListenerExists( AutomationEvents.SelectionItemPatternOnElementSelected ) ) - || ( AutomationPeer.ListenerExists( AutomationEvents.SelectionItemPatternOnElementAddedToSelection ) - || AutomationPeer.ListenerExists( AutomationEvents.SelectionItemPatternOnElementRemovedFromSelection ) ) ) - { - DataGridContextAutomationPeer peer = this.Peer; - - if( peer != null ) - { - peer.RaiseSelectionEvents( - ( IList )selectionInfo.RemovedItems, - ( IList )selectionInfo.AddedItems ); - } - } } #endregion @@ -1510,36 +1340,36 @@ namespace Xceed.Wpf.DataGrid #endregion - #region ItemsProperties/Column Auto update + #region ColumnManager Internal Property - private void HookToItemPropertiesChanged() + internal ColumnHierarchyManager ColumnManager { - DataGridCollectionViewBase itemsSourceCollection = this.ItemsSourceCollection as DataGridCollectionViewBase; - - if( itemsSourceCollection != null ) + get { - ItemPropertiesChangedEventManager.AddListener( itemsSourceCollection.ItemProperties, this ); + return m_columnManager; } } - private void UnhookToItemPropertiesChanged( DataGridCollectionViewBase itemsSourceCollection ) - { - if( itemsSourceCollection != null ) - { - ItemPropertiesChangedEventManager.RemoveListener( itemsSourceCollection.ItemProperties, this ); - } - } + private readonly ColumnHierarchyManager m_columnManager; - #endregion ItemsProperties/Column Auto update + #endregion - #region IsSettingFixedColumnCount Property + #region CanIncreaseColumnWidth Property - internal bool IsSettingFixedColumnCount + internal bool CanIncreaseColumnWidth { - get; - set; + get + { + return m_canIncreaseColumnWidth; + } + set + { + m_canIncreaseColumnWidth = value; + } } + private bool m_canIncreaseColumnWidth = true; + #endregion internal void SetCurrentColumnAndChangeSelection( ColumnBase newCurrentColumn ) @@ -1567,11 +1397,9 @@ namespace Xceed.Wpf.DataGrid } var oldPosition = SelectionRangePoint.TryCreateFromCurrent( this ); - var newPosition = new SelectionRangePoint( this, item, dataRowIndex, newCurrentColumn.VisiblePosition ); + var newPosition = SelectionRangePoint.TryCreateRangePoint( this, item, dataRowIndex, newCurrentColumn.VisiblePosition ); - m_dataGridControl.SelectionChangerManager.UpdateSelection( - oldPosition,newPosition, true, rowIsBeingEdited, - SelectionManager.UpdateSelectionSource.Navigation ); + m_dataGridControl.SelectionChangerManager.UpdateSelection( oldPosition, newPosition, true, rowIsBeingEdited, SelectionManager.UpdateSelectionSource.Navigation ); } } @@ -1615,59 +1443,44 @@ namespace Xceed.Wpf.DataGrid public bool IsGroupExpanded( CollectionViewGroup group ) { - return this.CustomItemContainerGenerator.IsGroupExpanded( group ); + return ( this.CustomItemContainerGenerator.IsGroupExpanded( group ) == true ); } - internal bool IsGroupExpandedCore( CollectionViewGroup group, bool recurseDetails ) + internal bool? IsGroupExpanded( CollectionViewGroup group, bool recurseDetails ) { - return this.CustomItemContainerGenerator.IsGroupExpandedCore( group, recurseDetails ); + return this.CustomItemContainerGenerator.IsGroupExpanded( group, recurseDetails ); } - public void ToggleGroupExpansion( CollectionViewGroup group ) + public bool ToggleGroupExpansion( CollectionViewGroup group ) { - this.CustomItemContainerGenerator.ToggleGroupExpansion( group ); + return this.CustomItemContainerGenerator.ToggleGroupExpansion( group ); } - public void ExpandGroup( CollectionViewGroup group ) + public bool ExpandGroup( CollectionViewGroup group ) { - this.CustomItemContainerGenerator.ExpandGroup( group ); + return this.CustomItemContainerGenerator.ExpandGroup( group ); } - internal bool ExpandGroupCore( CollectionViewGroup group, bool recurseDetails ) + internal bool ExpandGroup( CollectionViewGroup group, bool recurseDetails ) { - return this.CustomItemContainerGenerator.ExpandGroupCore( group, recurseDetails ); + return this.CustomItemContainerGenerator.ExpandGroup( group, recurseDetails ); } - public void CollapseGroup( CollectionViewGroup group ) + public bool CollapseGroup( CollectionViewGroup group ) { - this.CustomItemContainerGenerator.CollapseGroup( group ); + return this.CustomItemContainerGenerator.CollapseGroup( group ); } - internal bool CollapseGroupCore( CollectionViewGroup group, bool recurseDetails ) + internal bool CollapseGroup( CollectionViewGroup group, bool recurseDetails ) { - return this.CustomItemContainerGenerator.CollapseGroupCore( group, recurseDetails ); + return this.CustomItemContainerGenerator.CollapseGroup( group, recurseDetails ); } - internal bool AreDetailsExpanded( object dataItem ) + public bool AreDetailsExpanded( object dataItem ) { return this.CustomItemContainerGenerator.AreDetailsExpanded( dataItem ); } - internal void CollapseDetails( object dataItem ) - { - this.CustomItemContainerGenerator.CollapseDetails( dataItem ); - } - - internal void ExpandDetails( object dataItem ) - { - this.CustomItemContainerGenerator.ExpandDetails( dataItem ); - } - - internal void ToggleDetailExpansion( object dataItem ) - { - this.CustomItemContainerGenerator.ToggleDetails( dataItem ); - } - public Group GetGroupFromCollectionViewGroup( CollectionViewGroup collectionViewGroup ) { if( collectionViewGroup == null ) @@ -1683,7 +1496,7 @@ namespace Xceed.Wpf.DataGrid if( item == null ) return null; - DependencyObject container = null; + var container = default( DependencyObject ); if( ( m_detailConfig == null ) && ( item is DataTemplate ) ) { @@ -1693,7 +1506,9 @@ namespace Xceed.Wpf.DataGrid } if( container == null ) + { container = this.CustomItemContainerGenerator.ContainerFromItem( item ); + } return container; } @@ -1743,7 +1558,7 @@ namespace Xceed.Wpf.DataGrid //For the master level, before interrogating the Generator, I need to check for the items presence in the Fixed regions. if( ( m_detailConfig == null ) && ( dataTemplate != null ) ) { - Xceed.Wpf.DataGrid.Views.ViewBase view = m_dataGridControl.GetView(); + Views.ViewBase view = m_dataGridControl.GetView(); //Fixed header cannot have a Parent Group. if( view.FixedHeaders.Contains( dataTemplate ) == true ) @@ -1752,7 +1567,6 @@ namespace Xceed.Wpf.DataGrid //Fixed header cannot have a Parent Group. if( view.FixedFooters.Contains( dataTemplate ) == true ) return null; - } if( this.CustomItemContainerGenerator.IsInUse == true ) @@ -1798,62 +1612,56 @@ namespace Xceed.Wpf.DataGrid if( column == null ) throw new ArgumentNullException( "column" ); - string xPath = null; - PropertyPath propertyPath = null; + var xPath = default( string ); + var propertyPath = default( PropertyPath ); // Disable warning for DisplayMemberBinding when internaly used #pragma warning disable 618 - - Binding displayMemberBinding = column.DisplayMemberBinding as Binding; - + var displayMemberBinding = column.DisplayMemberBinding as Binding; #pragma warning restore 618 if( displayMemberBinding == null ) { - bool isBoundToDataGridUnboundItemProperty; - - displayMemberBinding = ItemsSourceHelper.AutoCreateDisplayMemberBinding( - column, this, dataItem, out isBoundToDataGridUnboundItemProperty ); + displayMemberBinding = ItemsSourceHelper.CreateDefaultBinding( + ItemsSourceHelper.CreateOrGetPropertyDescriptionFromColumn( this, column, dataItem.GetType() ) ); } - if( displayMemberBinding != null ) - { - xPath = displayMemberBinding.XPath; - propertyPath = displayMemberBinding.Path; - } - else - { + if( displayMemberBinding == null ) throw new DataGridInternalException( "DisplayMemberBinding is null.", m_dataGridControl ); - } - IValueConverter converter = new Xceed.Wpf.DataGrid.Converters.SourceDataConverter( ItemsSourceHelper.IsItemSupportingDBNull( dataItem ), CultureInfo.InvariantCulture ); + xPath = displayMemberBinding.XPath; + propertyPath = displayMemberBinding.Path; - BindingPathValueExtractor extractorForRead = new BindingPathValueExtractor( xPath, propertyPath, false, typeof( object ), converter, null, CultureInfo.InvariantCulture ); + var converter = new Xceed.Wpf.DataGrid.Converters.SourceDataConverter( ItemsSourceHelper.IsItemSupportingDBNull( dataItem ), CultureInfo.InvariantCulture ); - return extractorForRead; + return new BindingPathValueExtractor( xPath, propertyPath, false, typeof( object ), converter, null, CultureInfo.InvariantCulture ); } - //---------- INTERNAL METHODS ----------- + public IDisposable DeferColumnsUpdate() + { + return ColumnHierarchyManagerHelper.DeferColumnsUpdate( this ); + } - internal IDisposable DeferRestoreState() + public bool MoveColumnBefore( ColumnBase current, ColumnBase next ) { - return new DeferRestoreStateDisposable( this ); + return ColumnHierarchyManagerHelper.MoveColumnBefore( this, current, next ); } - internal void SetAssociatedAutomationPeer() + public bool MoveColumnAfter( ColumnBase current, ColumnBase previous ) { - DataGridContextAutomationPeer parentAutomationPeer = m_parentDataGridContext.Peer; + return ColumnHierarchyManagerHelper.MoveColumnAfter( this, current, previous ); + } - if( parentAutomationPeer == null ) - return; + public bool MoveColumnUnder( ColumnBase current, ColumnBase parent ) + { + return ColumnHierarchyManagerHelper.MoveColumnUnder( this, current, parent ); + } - DataGridContextAutomationPeer automationPeer = parentAutomationPeer.GetDetailPeer( m_parentItem, m_detailConfig ); + //---------- INTERNAL METHODS ----------- - if( automationPeer != null ) - { - this.Peer = automationPeer; - automationPeer.DataGridContext = this; - } + internal IDisposable DeferRestoreState() + { + return new DeferRestoreStateDisposable( this ); } internal void UpdatePublicSelectionProperties() @@ -1900,44 +1708,98 @@ namespace Xceed.Wpf.DataGrid internal void GetFirstSelectedItemFromStore( bool checkCellsStore, out int selectedItemIndex, out object selectedItem, out int selectedColumnIndex ) { - SelectionRangeWithItems newSelectedRangeWithItems = ( m_selectedItemsStore.Count == 0 ) ? - SelectionRangeWithItems.Empty : m_selectedItemsStore[ 0 ]; + var newSelectedRangeWithItems = ( m_selectedItemsStore.Count == 0 ) ? SelectionRangeWithItems.Empty : m_selectedItemsStore[ 0 ]; - if( newSelectedRangeWithItems.IsEmpty ) + try { - if( checkCellsStore ) + if( newSelectedRangeWithItems.IsEmpty ) { - SelectionCellRangeWithItems newSelectionCellRangeWithItems = ( m_selectedCellsStore.Count == 0 ) ? - SelectionCellRangeWithItems.Empty : m_selectedCellsStore[ 0 ]; + if( checkCellsStore ) + { + var newSelectionCellRangeWithItems = ( m_selectedCellsStore.Count == 0 ) ? SelectionCellRangeWithItems.Empty : m_selectedCellsStore[ 0 ]; - if( newSelectionCellRangeWithItems.ItemRange.IsEmpty ) + if( newSelectionCellRangeWithItems.ItemRange.IsEmpty ) + { + selectedColumnIndex = -1; + selectedItemIndex = -1; + selectedItem = null; + } + else + { + selectedColumnIndex = newSelectionCellRangeWithItems.ColumnRange.StartIndex; + selectedItemIndex = newSelectionCellRangeWithItems.ItemRange.StartIndex; + selectedItem = newSelectionCellRangeWithItems.ItemRangeWithItems.GetItem( this, 0 ); + } + } + else { selectedColumnIndex = -1; selectedItemIndex = -1; selectedItem = null; } - else - { - selectedColumnIndex = newSelectionCellRangeWithItems.ColumnRange.StartIndex; - selectedItemIndex = newSelectionCellRangeWithItems.ItemRange.StartIndex; - selectedItem = newSelectionCellRangeWithItems.ItemRangeWithItems.GetItem( this, 0 ); - } } else { selectedColumnIndex = -1; - selectedItemIndex = -1; - selectedItem = null; + selectedItemIndex = newSelectedRangeWithItems.Range.StartIndex; + selectedItem = newSelectedRangeWithItems.GetItem( this, 0 ); } } - else + catch( ArgumentOutOfRangeException ) { selectedColumnIndex = -1; - selectedItemIndex = newSelectedRangeWithItems.Range.StartIndex; - selectedItem = newSelectedRangeWithItems.GetItem( this, 0 ); + selectedItemIndex = -1; + selectedItem = null; } } + internal ColumnBase GetMatchingColumn( DataGridContext sourceContext, ColumnBase sourceColumn ) + { + if( ( sourceContext == null ) || ( sourceColumn == null ) ) + return null; + + if( sourceContext == this ) + return sourceColumn; + + var collectionView = sourceContext.ItemsSourceCollection as DataGridCollectionViewBase; + if( collectionView == null ) + return null; + + var sourceItemProperty = ItemsSourceHelper.GetItemPropertyFromProperty( collectionView.ItemProperties, sourceColumn.FieldName ); + if( sourceItemProperty == null ) + return null; + + var masterContext = sourceContext.RootDataGridContext; + var masterItemProperty = sourceItemProperty; + + if( masterContext != sourceContext ) + { + if( !sourceContext.ItemPropertyMap.TryGetMasterItemProperty( sourceItemProperty, out masterItemProperty ) ) + return null; + } + + Debug.Assert( masterItemProperty != null ); + if( masterItemProperty == null ) + return null; + + var currentItemProperty = masterItemProperty; + if( masterContext != this ) + { + if( !this.ItemPropertyMap.TryGetDetailItemProperty( masterItemProperty, out currentItemProperty ) ) + return null; + } + + Debug.Assert( currentItemProperty != null ); + if( currentItemProperty == null ) + return null; + + var columnName = PropertyRouteParser.Parse( currentItemProperty ); + if( string.IsNullOrEmpty( columnName ) ) + return null; + + return this.Columns[ columnName ]; + } + internal ColumnBase GetDefaultImageColumn() { if( !this.DefaultImageColumnDetermined ) @@ -1945,62 +1807,72 @@ namespace Xceed.Wpf.DataGrid if( this.Items.Count > 0 ) { this.DefaultImageColumnDetermined = true; - ItemsSourceHelper.FieldDescriptor fieldDescriptor; - object dataItem = this.Items.GetItemAt( 0 ); - foreach( ColumnBase visibleColumn in this.VisibleColumns ) + var dataItem = this.Items.GetItemAt( 0 ); + + foreach( var column in this.VisibleColumns ) { - if( this.ItemsSourceFieldDescriptors.TryGetValue( visibleColumn.FieldName, out fieldDescriptor ) ) + var key = PropertyRouteParser.Parse( column.FieldName ); + if( key == null ) + continue; + + var propertyDescriptionRoute = default( PropertyDescriptionRoute ); + if( !m_itemsSourcePropertyDescriptions.TryGetValue( key, out propertyDescriptionRoute ) ) + continue; + + var propertyDescription = propertyDescriptionRoute.Current; + var dataType = propertyDescription.DataType; + + if( typeof( ImageSource ).IsAssignableFrom( dataType ) ) { - if( typeof( ImageSource ).IsAssignableFrom( fieldDescriptor.DataType ) ) - { - m_defaultImageColumn = visibleColumn; - break; - } - else if( ( typeof( byte[] ).IsAssignableFrom( fieldDescriptor.DataType ) ) || - ( typeof( System.Drawing.Image ).IsAssignableFrom( fieldDescriptor.DataType ) ) ) - { - Xceed.Wpf.DataGrid.Converters.ImageConverter converter = new Xceed.Wpf.DataGrid.Converters.ImageConverter(); - object convertedValue = null; - object rawValue = null; + m_defaultImageColumn = column; + break; + } + else if( ( typeof( byte[] ).IsAssignableFrom( dataType ) ) || + ( typeof( System.Drawing.Image ).IsAssignableFrom( dataType ) ) ) + { + var converter = new Xceed.Wpf.DataGrid.Converters.ImageConverter(); + var convertedValue = default( object ); + var rawValue = default( object ); - try + try + { + if( propertyDescription.PropertyDescriptor == null ) { - if( fieldDescriptor.PropertyDescriptor == null ) + var dataRow = dataItem as System.Data.DataRow; + if( dataRow == null ) { - System.Data.DataRow dataRow = dataItem as System.Data.DataRow; - - if( dataRow == null ) + var dataRowView = dataItem as System.Data.DataRowView; + if( dataRowView != null ) { - System.Data.DataRowView dataRowView = dataItem as System.Data.DataRowView; - - if( dataRowView != null ) - rawValue = dataRowView[ fieldDescriptor.Name ]; - } - else - { - rawValue = dataRow[ fieldDescriptor.Name ]; + rawValue = dataRowView[ propertyDescription.Name ]; } } else { - rawValue = fieldDescriptor.PropertyDescriptor.GetValue( dataItem ); + rawValue = dataRow[ propertyDescription.Name ]; } - - if( rawValue != null ) - convertedValue = converter.Convert( rawValue, typeof( ImageSource ), null, System.Globalization.CultureInfo.CurrentCulture ); } - catch( NotSupportedException ) + else { - //suppress the exception, the byte[] is not an image. convertedValue will remain null + rawValue = propertyDescription.PropertyDescriptor.GetValue( dataItem ); } - if( convertedValue != null ) + if( rawValue != null ) { - m_defaultImageColumn = visibleColumn; - break; + convertedValue = converter.Convert( rawValue, typeof( ImageSource ), null, CultureInfo.CurrentCulture ); } } + catch( NotSupportedException ) + { + //suppress the exception, the byte[] is not an image. convertedValue will remain null + } + + if( convertedValue != null ) + { + m_defaultImageColumn = column; + break; + } } } } @@ -2093,57 +1965,6 @@ namespace Xceed.Wpf.DataGrid return this.CustomItemContainerGenerator.GetGroupFromItem( dataItem ); } - internal static void HandleColumnsCollectionChanged( - NotifyCollectionChangedEventArgs e, - ColumnCollection columns, - ReadOnlyColumnCollection visibleColumns, - HashedLinkedList columnsByVisiblePosition ) - { - if( columns == null ) - throw new ArgumentNullException( "columns" ); - - if( visibleColumns == null ) - throw new ArgumentNullException( "visibleColumns" ); - - if( columnsByVisiblePosition == null ) - throw new ArgumentNullException( "columnsByVisiblePosition" ); - - bool needGeneratorHardReset = false; - - if( e.OldItems != null ) - { - if( ( e.Action == NotifyCollectionChangedAction.Remove ) - || ( e.Action == NotifyCollectionChangedAction.Replace ) - || ( e.Action == NotifyCollectionChangedAction.Reset ) ) - { - if( e.OldItems.Count > 0 ) - needGeneratorHardReset = true; - } - } - - DataGridContext.UpdateVisibleColumns( columns, visibleColumns, columnsByVisiblePosition, e.NewItems, null ); - - // When a column is removed, we need to clear the Generator from every container to avoid problem - // when a Column with the same field name is removed thant reinserted with 2 different instances - if( needGeneratorHardReset ) - { - DataGridControl dataGridControl = columns.DataGridControl; - if( dataGridControl != null ) - { - if( dataGridControl.CustomItemContainerGenerator != null ) - { - dataGridControl.CustomItemContainerGenerator.RemoveAllAndNotify(); - } - - // We only reset the fixed region if the column is part of the master context - if( ( dataGridControl.DataGridContext != null ) && ( dataGridControl.DataGridContext.SourceDetailConfiguration == null ) ) - { - dataGridControl.ResetFixedRegions(); - } - } - } - } - internal IDisposable SetQueueBringIntoViewRestrictions( AutoScrollCurrentItemSourceTriggers trigger ) { return m_dataGridControl.SetQueueBringIntoViewRestrictions( trigger ); @@ -2161,9 +1982,7 @@ namespace Xceed.Wpf.DataGrid internal void NotifyItemsSourceChanged() { - this.NotifyPropertyChanged( "HasDetails" ); - - m_dataGridControl.QueueDataGridContextPeerChlidrenRefresh( this ); + this.OnPropertyChanged( "HasDetails" ); } internal void DelayBringIntoViewAndFocusCurrent( AutoScrollCurrentItemSourceTriggers trigger ) @@ -2203,42 +2022,37 @@ namespace Xceed.Wpf.DataGrid //set the flag that indicates that we are already processing a SetCurrent m_dataGridControl.IsSetCurrentInProgress = true; - DataGridContext oldCurrentContext = m_dataGridControl.CurrentContext; - DataGridContext newCurrentContext = this; + var oldCurrentContext = m_dataGridControl.CurrentContext; + var newCurrentContext = this; //store the previous public current item, so I can detect a change and lift the PropertyChanged for this properties - object oldCurrentItem = oldCurrentContext.InternalCurrentItem; - object oldPublicCurrentItem = oldCurrentContext.CurrentItem; - ColumnBase oldCurrentColumn = oldCurrentContext.CurrentColumn; - Row oldCurrentRow = oldCurrentContext.CurrentRow; + var oldCurrentItem = oldCurrentContext.InternalCurrentItem; + var oldPublicCurrentItem = oldCurrentContext.CurrentItem; + var oldCurrentColumn = oldCurrentContext.CurrentColumn; + var oldCurrentRow = oldCurrentContext.CurrentRow; - //if item is not realized or if the item passed is not a Data Item (header, footer or group), then the - //old current cell will be null - Cell oldCurrentCell = ( oldCurrentRow == null ) - ? null : oldCurrentRow.Cells[ oldCurrentColumn ]; + //if item is not realized or if the item passed is not a Data Item (header, footer or group), then the old current cell will be null + var oldCurrentCell = ( oldCurrentRow == null ) ? null : oldCurrentRow.Cells[ oldCurrentColumn ]; - Row newCurrentRow = ( containerRow != null ) - ? containerRow : Row.FromContainer( this.GetContainerFromItem( item ) ); + var newCurrentRow = ( containerRow != null ) ? containerRow : Row.FromContainer( this.GetContainerFromItem( item ) ); + var newCurrentCell = default( Cell ); //verify that set Current is not called on a column that cannot be current if( newCurrentRow != null ) { - if( ( column != null ) - && ( ( ( column.ReadOnly ) - && ( !newCurrentRow.Cells[ column ].GetCalculatedCanBeCurrent() ) ) ) ) + newCurrentCell = newCurrentRow.Cells[ column ]; + if( ( column != null ) && column.ReadOnly && ( newCurrentCell != null ) && !newCurrentCell.GetCalculatedCanBeCurrent() ) throw new DataGridException( "SetCurrent cannot be invoked if the column cannot be current.", m_dataGridControl ); } - //if item is not realized or if the item passed is not a Data Item (header, footer or group), then the - //new current cell will be null - Cell newCurrentCell = ( newCurrentRow == null ) ? null : newCurrentRow.Cells[ column ]; - bool currentCellChanged = ( newCurrentCell != oldCurrentCell ); + var currentCellChanged = ( newCurrentCell != oldCurrentCell ); - if( ( ( item != oldCurrentItem ) || ( oldCurrentContext != newCurrentContext ) ) - && ( oldCurrentRow != null ) ) + if( ( ( item != oldCurrentItem ) || ( oldCurrentContext != newCurrentContext ) ) && ( oldCurrentRow != null ) ) { if( Row.IsCellEditorDisplayConditionsSet( oldCurrentRow, CellEditorDisplayConditions.RowIsCurrent ) ) + { oldCurrentRow.RemoveDisplayEditorMatchingCondition( CellEditorDisplayConditions.RowIsCurrent ); + } oldCurrentRow.SetIsCurrent( false ); @@ -2251,29 +2065,31 @@ namespace Xceed.Wpf.DataGrid { //restore the Cell and the Row's IsCurrent Flag if( oldCurrentCell != null ) + { oldCurrentCell.SetIsCurrent( true ); + } oldCurrentRow.SetIsCurrent( true ); throw; } } - // For this if, the assumption is that current item hasn't changed, but current column does... (previous if will have - // caught the case where current item changed ). + //For this if, the assumption is that current item hasn't changed, but current column has... (previous if will have caught the case where current item changed). //if the currentCell has changed and the old current cell still exists. if( ( currentCellChanged ) && ( oldCurrentCell != null ) ) { //clear the CellIsCurrent editor display conditions if( Cell.IsCellEditorDisplayConditionsSet( oldCurrentCell, CellEditorDisplayConditions.CellIsCurrent ) ) + { oldCurrentCell.RemoveDisplayEditorMatchingCondition( CellEditorDisplayConditions.CellIsCurrent ); + } oldCurrentCell.SetIsCurrent( false ); try { - //cancel any ongoing editing on the cell. (this has no effect if row or cell is not being edited. - //this line can throw but no action is to be done. + //cancel any ongoing editing on the cell. (this has no effect if row or cell is not being edited. This line can throw but no action is to be done. oldCurrentCell.EndEdit(); } catch( DataGridException ) @@ -2283,10 +2099,9 @@ namespace Xceed.Wpf.DataGrid } } - if( ( item != oldCurrentItem ) - || ( oldCurrentContext != newCurrentContext ) ) + if( ( item != oldCurrentItem ) || ( oldCurrentContext != newCurrentContext ) ) { - DataGridCurrentChangingEventArgs currentChangingEventArgs = new DataGridCurrentChangingEventArgs( oldCurrentContext, oldCurrentItem, newCurrentContext, item, isCancelable ); + var currentChangingEventArgs = new DataGridCurrentChangingEventArgs( oldCurrentContext, oldCurrentItem, newCurrentContext, item, isCancelable ); m_dataGridControl.RaiseCurrentChanging( currentChangingEventArgs ); if( isCancelable && currentChangingEventArgs.Cancel ) @@ -2295,7 +2110,9 @@ namespace Xceed.Wpf.DataGrid if( oldCurrentRow != null ) { if( oldCurrentCell != null ) + { oldCurrentCell.SetIsCurrent( true ); + } oldCurrentRow.SetIsCurrent( true ); } @@ -2307,12 +2124,11 @@ namespace Xceed.Wpf.DataGrid //If they are different, clean the previously current DataGridContext if( oldCurrentContext != newCurrentContext ) { - oldCurrentContext.SetCurrentItemHelper( null, -1 ); - oldCurrentContext.SetInternalCurrentItemHelper( null ); - oldCurrentContext.SetInternalCurrentItemNamesTree( null ); + oldCurrentContext.SetCurrentItem( null, -1 ); + oldCurrentContext.SetInternalCurrentItem( null ); //preserve current column on the old DataGridContext - oldCurrentContext.SetIsCurrentHelper( false ); + oldCurrentContext.SetIsCurrent( false ); } if( !sourceDataItemIndex.HasValue ) @@ -2321,35 +2137,24 @@ namespace Xceed.Wpf.DataGrid } // All the stuff that can throw is done - newCurrentContext.SetInternalCurrentItemHelper( item ); - newCurrentContext.SetIsCurrentHelper( true ); - - if( ( item != null ) && ( item.GetType() == typeof( GroupHeaderFooterItem ) ) ) - { - GroupHeaderFooterItem groupHeaderItem = ( GroupHeaderFooterItem )item; - newCurrentContext.SetInternalCurrentItemNamesTree( newCurrentContext.CustomItemContainerGenerator.GetNamesTreeFromGroup( groupHeaderItem.Group ) ); - } - else - { - newCurrentContext.SetInternalCurrentItemNamesTree( null ); - } + newCurrentContext.SetInternalCurrentItem( item ); + newCurrentContext.SetIsCurrent( true ); // change the CurrentRow and CurentColumn if( ( item != null ) && ( sourceDataItemIndex.Value != -1 ) ) { - newCurrentContext.SetCurrentItemHelper( item, sourceDataItemIndex.Value ); + newCurrentContext.SetCurrentItem( item, sourceDataItemIndex.Value ); } else { - newCurrentContext.SetCurrentItemHelper( null, -1 ); + newCurrentContext.SetCurrentItem( null, -1 ); } newCurrentContext.SetCurrentColumnHelper( column ); m_dataGridControl.SetCurrentDataGridContextHelper( this ); // We must refetch the container for the current item in case EndEdit triggers a reset on the - // CustomItemContainerGenerator and remap this item to a container other than the one previously - // fetched + // CustomItemContainerGenerator and remap this item to a container other than the one previously fetched newCurrentRow = Row.FromContainer( newCurrentContext.GetContainerFromItem( item ) ); newCurrentCell = ( newCurrentRow == null ) ? null : newCurrentRow.Cells[ column ]; @@ -2362,7 +2167,9 @@ namespace Xceed.Wpf.DataGrid //update the RowIsCurrent display condition if( Row.IsCellEditorDisplayConditionsSet( newCurrentRow, CellEditorDisplayConditions.RowIsCurrent ) ) + { newCurrentRow.SetDisplayEditorMatchingCondition( CellEditorDisplayConditions.RowIsCurrent ); + } //Update the IsCurrent flag newCurrentRow.SetIsCurrent( true ); @@ -2370,15 +2177,13 @@ namespace Xceed.Wpf.DataGrid //if the current row changed, make sure to check the appropriate edition triggers. if( currentRowChanged == true ) { - //if enterEditTriggers tells to enter edition mode AND no current cell is going to be set on the new current row - if( ( newCurrentRow.IsEditTriggerSet( EditTriggers.RowIsCurrent ) ) - && ( newCurrentCell == null ) ) + //if EditTriggers tells to enter editing mode AND no current cell is set on the new current row + if( ( newCurrentRow.IsEditTriggerSet( EditTriggers.RowIsCurrent ) ) && ( newCurrentCell == null ) ) { //To prevent re-entrancy of the SetCurrent fonction (since Row.BeginEdit will call Cell.BeginEdit which will call SetCurrent if not current already) if( this.VisibleColumns.Count > 0 ) { - int firstFocusableColumn = NavigationHelper.GetFirstVisibleFocusableColumnIndex( this, newCurrentRow ); - + var firstFocusableColumn = NavigationHelper.GetFirstVisibleFocusableColumnIndex( this, newCurrentRow ); if( firstFocusableColumn < 0 ) throw new DataGridException( "Trying to edit while no cell is focusable. ", m_dataGridControl ); @@ -2395,7 +2200,9 @@ namespace Xceed.Wpf.DataGrid { //update the CellIsCurrent display condition if( Cell.IsCellEditorDisplayConditionsSet( newCurrentCell, CellEditorDisplayConditions.CellIsCurrent ) ) + { newCurrentCell.SetDisplayEditorMatchingCondition( CellEditorDisplayConditions.CellIsCurrent ); + } newCurrentCell.SetIsCurrent( true ); @@ -2436,14 +2243,21 @@ namespace Xceed.Wpf.DataGrid { if( m_dataGridControl.IsBringIntoViewAllowed( trigger ) ) { - if( newCurrentCell != null ) + if( !m_dataGridControl.IsBringIntoViewDelayed ) { - newCurrentCell.BringIntoView(); + if( newCurrentCell != null ) + { + newCurrentCell.BringIntoView(); + } + else + { + // Ensure the item is visible visible + newCurrentRow.BringIntoView(); + } } else { - // Ensure the item is visible visible - newCurrentRow.BringIntoView(); + m_dataGridControl.DelayBringIntoViewAndFocusCurrent( trigger ); } } @@ -2494,20 +2308,23 @@ namespace Xceed.Wpf.DataGrid } finally { - m_dataGridControl.SelectionChangerManager.End( false, false, false ); + m_dataGridControl.SelectionChangerManager.End( false, false ); } } if( this.CurrentItem != oldPublicCurrentItem ) - this.NotifyPropertyChanged( "CurrentItem" ); + { + this.OnPropertyChanged( "CurrentItem" ); + } if( column != oldCurrentColumn ) - this.NotifyPropertyChanged( "CurrentColumn" ); + { + this.OnPropertyChanged( "CurrentColumn" ); + } - if( ( item != oldCurrentItem ) - || ( oldCurrentContext != newCurrentContext ) ) + if( ( item != oldCurrentItem ) || ( oldCurrentContext != newCurrentContext ) ) { - DataGridCurrentChangedEventArgs currentChangedEventArgs = new DataGridCurrentChangedEventArgs( oldCurrentContext, oldCurrentItem, newCurrentContext, item ); + var currentChangedEventArgs = new DataGridCurrentChangedEventArgs( oldCurrentContext, oldCurrentItem, newCurrentContext, item ); m_dataGridControl.RaiseCurrentChanged( currentChangedEventArgs ); } } @@ -2564,175 +2381,33 @@ namespace Xceed.Wpf.DataGrid case NotifyCollectionChangedAction.Reset: - groupLevelDescriptions.Clear(); - - foreach( GroupDescription desc in groupDescriptions ) - { - GroupLevelDescription newInfo = DataGridContext.CreateGroupLevelDescription( columns, desc ); - - groupLevelDescriptions.Add( newInfo ); - } - - break; - - case NotifyCollectionChangedAction.Move: - - GroupLevelDescription movedGroupLevelDescription = groupLevelDescriptions[ e.OldStartingIndex ]; - groupLevelDescriptions.RemoveAt( e.OldStartingIndex ); - groupLevelDescriptions.Insert( e.NewStartingIndex, movedGroupLevelDescription ); - - break; - - case NotifyCollectionChangedAction.Replace: - - groupLevelDescriptions.RemoveAt( e.OldStartingIndex ); - GroupLevelDescription replaceInfo = DataGridContext.CreateGroupLevelDescription( columns, ( GroupDescription )e.NewItems[ 0 ] ); - - groupLevelDescriptions.Insert( e.NewStartingIndex, replaceInfo ); - - break; - } - } - - internal static void UpdateVisibleColumns( - ColumnCollection columns, - ReadOnlyColumnCollection visibleColumns, - HashedLinkedList columnsByVisiblePosition, - IList triggeringColumns, - ColumnVisiblePositionChangedEventArgs visiblePositionChangedArgs ) - { - if( columns == null ) - throw new ArgumentNullException( "columns" ); - - if( visibleColumns == null ) - throw new ArgumentNullException( "visibleColumns" ); - - if( columnsByVisiblePosition == null ) - throw new ArgumentNullException( "columnsByVisiblePosition" ); - - if( columns.ProcessingVisibleColumnsUpdate.IsSet ) - return; - - if( columns.IsDeferVisibleColumnsUpdate ) - return; - - using( columns.ProcessingVisibleColumnsUpdate.Set() ) - { - columns.NotifyVisibleColumnsUpdating(); - - columnsByVisiblePosition.Clear(); - - int columnCount = columns.Count; - ColumnBase currentColumn; - - // Add the Columns which are not part of the triggering columns collection. - for( int currentIndex = 0; currentIndex < columnCount; currentIndex++ ) - { - currentColumn = columns[ currentIndex ]; - - if( ( triggeringColumns == null ) || ( !triggeringColumns.Contains( currentColumn ) ) ) - { - DataGridContext.InsertColumnByVisiblePosition( columnsByVisiblePosition, currentColumn ); - } - } - - // Add the Columns which are part of the triggering columns collection - // (their VisiblePosition have priority over the existing ones). - if( triggeringColumns != null ) - { - if( visiblePositionChangedArgs == null ) - { - // From a ColumnCollection change - foreach( ColumnBase column in triggeringColumns ) - { - DataGridContext.InsertColumnByVisiblePosition( columnsByVisiblePosition, column ); - } - } - else - { - // From a Column.VisiblePosition change - ColumnBase column = visiblePositionChangedArgs.TriggeringColumn; - - LinkedListNode oldPositionNode = null; - LinkedListNode listNode = columnsByVisiblePosition.First; - - while( listNode != null ) - { - if( listNode.Value.VisiblePosition >= column.VisiblePosition ) - { - oldPositionNode = listNode; - break; - } - listNode = listNode.Next; - } - - // If there were already some columns, the desired. If oldPositionNode is null, it means - // there were no column at the desired VisiblePosition. We must add it at the end of the - // list since the new column VisiblePosition is greater than the actual columns VisiblePosition - if( oldPositionNode != null ) - { - if( visiblePositionChangedArgs.PositionDelta > 0 ) - { - columnsByVisiblePosition.AddAfter( oldPositionNode, column ); - } - else if( visiblePositionChangedArgs.PositionDelta < 0 ) - { - columnsByVisiblePosition.AddBefore( oldPositionNode, column ); - } - } - else - { - columnsByVisiblePosition.AddLast( column ); - } - } - } + groupLevelDescriptions.Clear(); - var dataGridControl = columns.DataGridControl; - var mainColumn = columns.MainColumn; - if( ( dataGridControl != null ) && ( mainColumn != null ) && ( dataGridControl.AreDetailsFlatten ) ) - { - var firstNode = columnsByVisiblePosition.First; - if( ( firstNode == null ) || ( firstNode.Value != mainColumn ) ) + foreach( GroupDescription desc in groupDescriptions ) { - columnsByVisiblePosition.Remove( mainColumn ); - columnsByVisiblePosition.AddFirst( mainColumn ); + GroupLevelDescription newInfo = DataGridContext.CreateGroupLevelDescription( columns, desc ); + + groupLevelDescriptions.Add( newInfo ); } - } - // Fill the VisibleColumns collection and - // update all the columns' VisiblePosition, IsFirstVisible, and IsLastVisible properties. - visibleColumns.InternalClear(); + break; - int i = 0; - LinkedListNode columnNode = columnsByVisiblePosition.First; + case NotifyCollectionChangedAction.Move: - // While is used to be sure Columns are returned in ascendant order - while( columnNode != null ) - { - currentColumn = columnNode.Value; + GroupLevelDescription movedGroupLevelDescription = groupLevelDescriptions[ e.OldStartingIndex ]; + groupLevelDescriptions.RemoveAt( e.OldStartingIndex ); + groupLevelDescriptions.Insert( e.NewStartingIndex, movedGroupLevelDescription ); - using( currentColumn.InhibitVisiblePositionChanging() ) - { - currentColumn.VisiblePosition = i++; - currentColumn.ClearIsFirstVisible(); - currentColumn.ClearIsLastVisible(); + break; - if( currentColumn.Visible ) - { - visibleColumns.InternalAdd( currentColumn ); - } - } + case NotifyCollectionChangedAction.Replace: - columnNode = columnNode.Next; - } + groupLevelDescriptions.RemoveAt( e.OldStartingIndex ); + GroupLevelDescription replaceInfo = DataGridContext.CreateGroupLevelDescription( columns, ( GroupDescription )e.NewItems[ 0 ] ); - if( visibleColumns.Count > 0 ) - { - visibleColumns[ 0 ].SetIsFirstVisible( true ); - visibleColumns[ visibleColumns.Count - 1 ].SetIsLastVisible( true ); - } + groupLevelDescriptions.Insert( e.NewStartingIndex, replaceInfo ); - columns.DispatchNotifyVisibleColumnsUpdated(); + break; } } @@ -2799,7 +2474,7 @@ namespace Xceed.Wpf.DataGrid } finally { - selectionManager.End( false, false, false ); + selectionManager.End( false, false ); } } @@ -2868,6 +2543,8 @@ namespace Xceed.Wpf.DataGrid return false; } + + //---------- PRIVATE METHODS ---------- private void ClearViewPropertyBindings() @@ -3122,15 +2799,16 @@ namespace Xceed.Wpf.DataGrid { Debug.Assert( this.Columns[ args.AutoFilterColumnFieldName ] != null ); - ReadOnlyObservableHashList readOnlyObservableHashList = null; - - if( this.DistinctValues == null ) + var distinctValues = this.DistinctValues; + if( distinctValues == null ) return; + var readOnlyObservableHashList = default( ReadOnlyObservableHashList ); + // We force the creation of DistinctValues for this field in every DataGridCollectionView - if( this.DistinctValues.TryGetValue( args.AutoFilterColumnFieldName, out readOnlyObservableHashList ) ) + if( distinctValues.TryGetValue( args.AutoFilterColumnFieldName, out readOnlyObservableHashList ) ) { - foreach( object item in readOnlyObservableHashList ) + foreach( var item in readOnlyObservableHashList ) { args.DistinctValues.Add( item ); } @@ -3244,31 +2922,11 @@ namespace Xceed.Wpf.DataGrid } } - private void CreateStandaloneCollections() - { - m_columns = new ColumnCollection( this.DataGridControl, null ); - VisibilityChangingEventManager.AddListener( m_columns, this ); - VisibilityChangedEventManager.AddListener( m_columns, this ); - - m_visibleColumns = new ReadOnlyColumnCollection(); - m_columnsByVisiblePosition = new HashedLinkedList(); - m_groupLevelDescriptions = new GroupLevelDescriptionCollection(); - - //in this particular case, I need to create a SortDescriptionsSyncContext to ensure I will be able to synchronize access to the sort descriptions collection. - m_sortDescriptionsSyncContext = new SortDescriptionsSyncContext(); - - //Register to the Columns Collection's CollectionChanged event to manage the Removal of the CurrentColumn. - CollectionChangedEventManager.AddListener( m_columns, this ); - - // Register to the VisibleColumnsChanged to update, if need be, the columns desired width when column stretching is active and there's a column reordering. - CollectionChangedEventManager.AddListener( m_visibleColumns, this ); - } - private void HandleMasterColumnsCollectionChanged( NotifyCollectionChangedEventArgs e ) { - bool removeCurrentColumn = false; - bool needGeneratorHardReset = false; - ColumnBase currentColumn = this.CurrentColumn; + var removeCurrentColumn = false; + var needGeneratorHardReset = false; + var currentColumn = this.CurrentColumn; //If( e.Action == Add ), there is nothing to do. @@ -3297,26 +2955,29 @@ namespace Xceed.Wpf.DataGrid needGeneratorHardReset = true; } } + //Nothing to do because the way to change the visible position of a column is through its VisiblePosition property. else if( e.Action == NotifyCollectionChangedAction.Move ) { - //Nothing to do because the way to change the visible position of a column is through its VisiblePosition property. return; } - ColumnBase closestColumn = null; + var closestColumn = default( ColumnBase ); + //Select the current column's closest visible column while its possible if( removeCurrentColumn ) { closestColumn = DataGridContext.GetClosestColumn( currentColumn, this.ColumnsByVisiblePosition ); } - // When a column is removed, we need to clear the Generator from every container to avoid problem - // when a Column with the same field name is removed thant reinserted with 2 different instances + // When a column is removed, we need to clear the Generator from every container to avoid problems + // if the column is added again, but using a different instance (i.e. a new column with the same fieldname). if( needGeneratorHardReset ) { // We only reset the fixed region if the column is part of the master context if( this.SourceDetailConfiguration == null ) + { this.DataGridControl.ResetFixedRegions(); + } this.DataGridControl.CustomItemContainerGenerator.RemoveAllAndNotify(); } @@ -3329,10 +2990,10 @@ namespace Xceed.Wpf.DataGrid this.UpdateColumnSortCommand.Execute(); } - DataGridContext.HandleColumnsCollectionChanged( e, this.Columns, this.VisibleColumns as ReadOnlyColumnCollection, this.ColumnsByVisiblePosition ); - if( removeCurrentColumn ) { + // Now that the columns collections have been updated, it is time to set the new current column if necessary. + // The new current column that was identified earlier may have been removed from the visible columns after the collections update. if( ( closestColumn != null ) && !this.Columns.Contains( closestColumn ) ) { closestColumn = null; @@ -3341,14 +3002,10 @@ namespace Xceed.Wpf.DataGrid this.SetCurrentColumnCore( closestColumn, false, m_dataGridControl.SynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.ColumnsCollectionChanged ); } - if( m_columns != null ) - { - ForeignKeyConfiguration.UpdateColumnsForeignKeyConfigurations( - m_columns.FieldNameToColumnDictionary, - this.ItemsSourceCollection, - this.ItemsSourceFieldDescriptors, - this.AutoCreateForeignKeyConfigurations ); - } + ForeignKeyConfiguration.UpdateColumnsForeignKeyConfigurations( this.Columns, + this.ItemsSourceCollection, + m_itemsSourcePropertyDescriptions, + this.AutoCreateForeignKeyConfigurations ); } internal static ColumnBase GetClosestColumn( ColumnBase reference, HashedLinkedList columnsByVisiblePosition ) @@ -3375,11 +3032,11 @@ namespace Xceed.Wpf.DataGrid return newColumn; } - private void SetupViewProperties( bool initialization = false ) + private void SetupViewProperties() { this.ClearViewPropertyBindings(); - Views.ViewBase view = m_dataGridControl.GetView( !initialization ); + Views.ViewBase view = m_dataGridControl.GetView(); if( view == null ) return; @@ -3401,13 +3058,157 @@ namespace Xceed.Wpf.DataGrid //Note: we place the shared and non-shared properties in the same pool (makes no differences beyond this point ). m_viewProperties.Add( viewProperty ); - this.NotifyPropertyChanged( dependencyProperty.Name ); + this.OnPropertyChanged( dependencyProperty.Name ); } } private void InitializeViewProperties() { - TableflowView.SetFixedColumnSplitterTranslation( this, new TranslateTransform() ); + if( !this.IsAFlattenDetail ) + { + TableflowView.SetFixedColumnSplitterTranslation( this, new TranslateTransform() ); + } + } + + private void HookToItemPropertiesChanged() + { + var collectionView = this.ItemsSourceCollection as DataGridCollectionViewBase; + if( collectionView == null ) + return; + + this.RegisterItemProperties( collectionView.ItemProperties ); + } + + private void UnhookToItemPropertiesChanged( DataGridCollectionViewBase collectionView ) + { + if( collectionView == null ) + return; + + this.UnregisterItemProperties( collectionView.ItemProperties ); + } + + private void UpdateColumns() + { + Debug.Assert( m_detailConfig == null ); + + ItemsSourceHelper.ResetPropertyDescriptions( m_itemsSourcePropertyDescriptions, m_itemPropertyMap, m_dataGridControl, m_dataGridControlItemsSource ); + + if( m_dataGridControl.AutoCreateColumns ) + { + ItemsSourceHelper.UpdateColumnsFromPropertyDescriptions( m_columnManager, m_dataGridControl.DefaultCellEditors, m_itemsSourcePropertyDescriptions, this.AutoCreateForeignKeyConfigurations ); + } + } + + private void RegisterItemProperties( DataGridItemPropertyCollection itemProperties ) + { + if( itemProperties == null ) + return; + + CollectionChangedEventManager.AddListener( itemProperties, this ); + + foreach( var itemProperty in itemProperties ) + { + this.RegisterItemProperty( itemProperty ); + } + } + + private void UnregisterItemProperties( DataGridItemPropertyCollection itemProperties ) + { + if( itemProperties == null ) + return; + + foreach( var itemProperty in itemProperties ) + { + this.UnregisterItemProperty( itemProperty ); + } + + CollectionChangedEventManager.RemoveListener( itemProperties, this ); + } + + private void RegisterItemProperty( DataGridItemPropertyBase itemProperty ) + { + if( itemProperty == null ) + return; + + PropertyChangedEventManager.AddListener( itemProperty, this, DataGridItemPropertyBase.ItemPropertiesInternalPropertyName ); + this.RegisterItemProperties( itemProperty.ItemPropertiesInternal ); + } + + private void UnregisterItemProperty( DataGridItemPropertyBase itemProperty ) + { + if( itemProperty == null ) + return; + + this.UnregisterItemProperties( itemProperty.ItemPropertiesInternal ); + PropertyChangedEventManager.RemoveListener( itemProperty, this, DataGridItemPropertyBase.ItemPropertiesInternalPropertyName ); + } + + private void OnItemPropertiesCollectionChanged( DataGridItemPropertyCollection collection, NotifyCollectionChangedEventArgs e ) + { + Debug.Assert( m_detailConfig == null ); + + var rootCollection = ItemsSourceHelper.GetRootCollection( collection ); + if( rootCollection == null ) + return; + + if( rootCollection == ( ( DataGridCollectionViewBase )m_dataGridControlItemsSource ).ItemProperties ) + { + if( e.Action == NotifyCollectionChangedAction.Reset ) + throw new NotSupportedException(); + + if( e.Action == NotifyCollectionChangedAction.Move ) + return; + + if( e.OldItems != null ) + { + foreach( DataGridItemPropertyBase itemProperty in e.OldItems ) + { + this.UnregisterItemProperty( itemProperty ); + } + } + + if( e.NewItems != null ) + { + foreach( DataGridItemPropertyBase itemProperty in e.NewItems ) + { + this.RegisterItemProperty( itemProperty ); + } + } + + this.UpdateColumns(); + } + else + { + Debug.Fail( "The collection is not linked to the collection view's item properties." ); + this.UnregisterItemProperties( collection ); + } + } + + private void OnItemPropertyPropertyChanged( DataGridItemPropertyBase itemProperty, PropertyChangedEventArgs e ) + { + Debug.Assert( m_detailConfig == null ); + + var rootCollection = ItemsSourceHelper.GetRootCollection( itemProperty ); + if( rootCollection == null ) + return; + + if( rootCollection != ( ( DataGridCollectionViewBase )m_dataGridControlItemsSource ).ItemProperties ) + { + Debug.Fail( "The collection is not linked to the detail configuration's item properties." ); + this.UnregisterItemProperty( itemProperty ); + return; + } + + if( string.IsNullOrEmpty( e.PropertyName ) || ( e.PropertyName == DataGridItemPropertyBase.ItemPropertiesInternalPropertyName ) ) + { + var itemProperties = itemProperty.ItemPropertiesInternal; + if( itemProperties != null ) + { + this.UnregisterItemProperties( itemProperties ); + this.RegisterItemProperties( itemProperties ); + this.UpdateColumns(); + } + } } private void OnDetailConfigRequestingDelayBringIntoViewAndFocusCurrent( object sender, RequestingDelayBringIntoViewAndFocusCurrentEventArgs e ) @@ -3465,14 +3266,7 @@ namespace Xceed.Wpf.DataGrid protected override void OnPropertyChanged( DependencyPropertyChangedEventArgs e ) { base.OnPropertyChanged( e ); - - if( ( m_viewProperties != null ) && ( m_viewProperties.Count > 0 ) ) - { - if( m_viewProperties.Contains( new Views.ViewBase.ViewPropertyStruct( e.Property ) ) == true ) - { - this.NotifyPropertyChanged( e.Property.Name ); - } - } + this.OnPropertyChanged( e.Property.Name ); } //---------- INTERFACES ---------- @@ -3481,10 +3275,13 @@ namespace Xceed.Wpf.DataGrid public event PropertyChangedEventHandler PropertyChanged; - private void NotifyPropertyChanged( string propertyName ) + private void OnPropertyChanged( string propertyName ) { - if( this.PropertyChanged != null ) - this.PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) ); + var handler = this.PropertyChanged; + if( handler == null ) + return; + + handler.Invoke( this, new PropertyChangedEventArgs( propertyName ) ); } #endregion @@ -3492,85 +3289,79 @@ namespace Xceed.Wpf.DataGrid #region IWeakEventListener Members bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) + { + return this.OnReceiveWeakEvent( managerType, sender, e ); + } + + private bool OnReceiveWeakEvent( Type managerType, object sender, EventArgs e ) { if( managerType == typeof( CollectionChangedEventManager ) ) { + var eventArgs = ( NotifyCollectionChangedEventArgs )e; + if( sender == m_items ) { - var args = ( ( NotifyCollectionChangedEventArgs )e ).GetRangeActionOrSelf(); + var args = eventArgs.GetRangeActionOrSelf(); this.Items_CollectionChanged( sender, args ); - return true; } if( sender == this.DetailConfigurations ) { - this.NotifyPropertyChanged( "HasDetails" ); - return true; + this.OnPropertyChanged( "HasDetails" ); } - else if( sender == m_columns ) + else if( sender == m_columnManager.Columns ) { //Master Level columns collection changed - this.HandleMasterColumnsCollectionChanged( ( NotifyCollectionChangedEventArgs )e ); - return true; + this.HandleMasterColumnsCollectionChanged( eventArgs ); } else if( sender == this.VisibleColumns ) { - ColumnStretchMode mode = ColumnStretchMode.None; + var mode = ColumnStretchMode.None; if( this.GetViewPropertyValue( "ColumnStretchMode", ref mode ) ) { if( ( mode == ColumnStretchMode.First ) || ( mode == ColumnStretchMode.Last ) ) { - NotifyCollectionChangedEventArgs notifyArgs = ( NotifyCollectionChangedEventArgs )e; - - if( notifyArgs.NewItems != null ) + if( eventArgs.NewItems != null ) { - foreach( ColumnBase column in notifyArgs.NewItems ) + foreach( ColumnBase column in eventArgs.NewItems ) { column.ClearValue( ColumnBase.DesiredWidthProperty ); } } } } - - return true; } else if( sender == m_items.SortDescriptions ) { - this.OnSortDescriptionsChanged( sender, ( NotifyCollectionChangedEventArgs )e ); - return true; + this.OnSortDescriptionsChanged( sender, eventArgs ); } else if( sender == m_items.GroupDescriptions ) { - this.OnGroupDescriptionsChanged( sender, ( NotifyCollectionChangedEventArgs )e ); - return true; + this.OnGroupDescriptionsChanged( sender, eventArgs ); + } + else if( sender is DataGridItemPropertyCollection ) + { + this.OnItemPropertiesCollectionChanged( ( DataGridItemPropertyCollection )sender, eventArgs ); } } - else if( managerType == typeof( VisibilityChangingEventManager ) ) - { - DataGridContext.UnselectAllCells( this ); - - return true; - } - else if( managerType == typeof( VisibilityChangedEventManager ) ) + else if( managerType == typeof( PropertyChangedEventManager ) ) { - var wrappedEventArgs = ( ColumnCollection.WrappedEventEventArgs )e; - - DataGridContext.UpdateVisibleColumns( this.Columns, this.VisibleColumns as ReadOnlyColumnCollection, this.ColumnsByVisiblePosition, - new object[] { wrappedEventArgs.WrappedSender }, wrappedEventArgs.WrappedEventArgs as ColumnVisiblePositionChangedEventArgs ); + var eventArgs = ( PropertyChangedEventArgs )e; - return true; + if( sender is DataGridItemPropertyBase ) + { + this.OnItemPropertyPropertyChanged( ( DataGridItemPropertyBase )sender, eventArgs ); + } } - else if( managerType == typeof( VisibleColumnsUpdatingEventManager ) ) + else if( managerType == typeof( ColumnsLayoutChangingEventManager ) ) { DataGridContext.UnselectAllCells( this ); - - return true; } - else if( managerType == typeof( VisibleColumnsUpdatedEventManager ) ) + else if( managerType == typeof( ColumnsLayoutChangedEventManager ) ) { // Only force a reset if at least one Row has not used an IVirtualizingCellsHost as PART_CellsHost - if( this.DataGridControl.ForceGeneratorReset == true ) + if( m_dataGridControl.ForceGeneratorReset ) { //forces the collection view to refresh (therefore, regenerates all the items ). this.CustomItemContainerGenerator.RemoveAllAndNotify(); @@ -3583,18 +3374,17 @@ namespace Xceed.Wpf.DataGrid } this.DefaultImageColumnDetermined = false; - return true; } else if( managerType == typeof( PreBatchCollectionChangedEventManager ) ) { Debug.Assert( m_deferSelectionChangedOnItemsCollectionChanged == null ); - if( m_deferSelectionChangedOnItemsCollectionChanged == null ) + // When using DataGridVirtualizingCollectionViewBase, we should keep the "Replace" action + // in order to call UpdateSelectionAfterSourceCollectionChanged with a Replace instead of a Reset. + if( m_deferSelectionChangedOnItemsCollectionChanged == null && !( sender is DataGridVirtualizingCollectionViewBase ) ) { m_deferSelectionChangedOnItemsCollectionChanged = new DeferSelectionChangedOnItemsCollectionChangedDisposable( this ); } - - return true; } else if( managerType == typeof( PostBatchCollectionChangedEventManager ) ) { @@ -3604,77 +3394,51 @@ namespace Xceed.Wpf.DataGrid m_deferSelectionChangedOnItemsCollectionChanged = null; disposable.Dispose(); } - - return true; } else if( managerType == typeof( RealizedContainersRequestedEventManager ) ) { - RealizedContainersRequestedEventArgs eventArgs = ( RealizedContainersRequestedEventArgs )e; + var eventArgs = ( RealizedContainersRequestedEventArgs )e; this.GetRealizedItems( eventArgs.RealizedContainers ); - return true; } else if( managerType == typeof( DistinctValuesRequestedEventManager ) ) { - DistinctValuesRequestedEventArgs eventArgs = ( DistinctValuesRequestedEventArgs )e; + var eventArgs = ( DistinctValuesRequestedEventArgs )e; this.MergeDistinctValues( eventArgs ); - return true; } else if( managerType == typeof( AllowDetailToggleChangedEventManager ) ) { - this.NotifyPropertyChanged( "AllowDetailToggle" ); - return true; + this.OnPropertyChanged( "AllowDetailToggle" ); } else if( managerType == typeof( ViewChangedEventManager ) ) { this.SetupViewProperties(); this.InitializeViewProperties(); - return true; } else if( managerType == typeof( CurrentColumnChangedEventManager ) ) { - this.NotifyPropertyChanged( "CurrentColumn" ); - return true; + this.OnPropertyChanged( "CurrentColumn" ); } else if( managerType == typeof( GroupConfigurationSelectorChangedEventManager ) ) { this.OnGroupConfigurationSelectorChanged(); - return true; } else if( managerType == typeof( DetailVisibilityChangedEventManager ) ) { - this.NotifyPropertyChanged( "HasDetails" ); - return true; + this.OnPropertyChanged( "HasDetails" ); } else if( managerType == typeof( MaxGroupLevelsChangedEventManager ) ) { - this.NotifyPropertyChanged( "MaxGroupLevels" ); - return true; + this.OnPropertyChanged( "MaxGroupLevels" ); } else if( managerType == typeof( MaxSortLevelsChangedEventManager ) ) { - this.NotifyPropertyChanged( "MaxSortLevels" ); - return true; - } - else if( managerType == typeof( ItemPropertiesChangedEventManager ) ) - { - this.ItemsSourceFieldDescriptors = null; - bool autoCreateColumns = ( m_detailConfig == null ) ? m_dataGridControl.AutoCreateColumns : m_detailConfig.AutoCreateColumns; - - if( autoCreateColumns ) - { - ItemsSourceHelper.UpdateColumnsOnItemsPropertiesChanged( - this.DataGridControl, this.Columns, this.AutoCreateForeignKeyConfigurations, - ( NotifyCollectionChangedEventArgs )e, ( DataGridItemPropertyCollection )sender ); - } - - return true; + this.OnPropertyChanged( "MaxSortLevels" ); } else if( managerType == typeof( ItemsSourceChangeCompletedEventManager ) ) { var dataGridCollectionViewBase = m_dataGridControlItemsSource as DataGridCollectionViewBase; - // GenerateColumnsFromItemsSourceFields is already done in DataGridControl.ProcessDelayedItemsSourceChanged - // no need to do it here. + // GenerateColumnsFromItemsSourceFields is already done in DataGridControl.ProcessDelayedItemsSourceChanged no need to do it here. this.UnhookToItemPropertiesChanged( dataGridCollectionViewBase ); if( dataGridCollectionViewBase != null ) @@ -3705,11 +3469,13 @@ namespace Xceed.Wpf.DataGrid collectionView.PrepareRootContextForDeferRefresh( this ); } } - - return true; + } + else + { + return false; } - return false; + return true; } #endregion @@ -3717,14 +3483,13 @@ namespace Xceed.Wpf.DataGrid #region Private Fields private BitVector32 m_flags = new BitVector32(); - private CurrencyManager m_currencyManager; - private List m_viewProperties = new List(); - PropertyDescriptorCollection m_viewPropertiesDescriptors; // = null + private readonly CurrencyManager m_currencyManager; + private readonly ICollection m_viewProperties = new List(); + private PropertyDescriptorCollection m_viewPropertiesDescriptors; // = null private DefaultDetailConfiguration m_defaultDetailConfiguration; // = null - private RecyclingManager m_recyclingManager; // = null private ColumnBase m_defaultImageColumn; // = null private int m_deferRestoreStateCount; // = 0; - private Dictionary m_sizeStateDictionary = new Dictionary(); + private readonly Dictionary m_sizeStateDictionary = new Dictionary(); private IEnumerable m_dataGridControlItemsSource; private DeferSelectionChangedOnItemsCollectionChangedDisposable m_deferSelectionChangedOnItemsCollectionChanged; // = null @@ -3808,20 +3573,20 @@ namespace Xceed.Wpf.DataGrid // We only cache the full property list. if( m_viewPropertiesDescriptors == null ) { - Xceed.Wpf.DataGrid.Views.ViewBase view = this.DataGridControl.GetView(); + var view = m_dataGridControl.GetView(); Debug.Assert( view != null ); if( view == null ) return PropertyDescriptorCollection.Empty; - ViewBindingPropertyDescriptor[] properties = new ViewBindingPropertyDescriptor[ m_viewProperties.Count ]; - for( int i = 0; i < m_viewProperties.Count; i++ ) + var properties = new ViewBindingPropertyDescriptor[ m_viewProperties.Count ]; + var defaultDetailConfiguration = this.GetDefaultDetailConfigurationForContext(); + var index = 0; + + foreach( var property in m_viewProperties ) { - properties[ i ] = new ViewBindingPropertyDescriptor( m_detailConfig, - this.GetDefaultDetailConfigurationForContext(), - m_dataGridControl.GetView(), - m_viewProperties[ i ].DependencyProperty, - m_viewProperties[ i ].ViewPropertyMode ); + properties[ index ] = new ViewBindingPropertyDescriptor( m_detailConfig, defaultDetailConfiguration, view, property.DependencyProperty, property.ViewPropertyMode ); + index++; } m_viewPropertiesDescriptors = new PropertyDescriptorCollection( properties ); @@ -3845,57 +3610,6 @@ namespace Xceed.Wpf.DataGrid #endregion - #region Automation - - private static readonly DependencyPropertyKey AutomationPeerPropertyKey = - DependencyProperty.RegisterReadOnly( "AutomationPeer", typeof( DataGridContextAutomationPeer ), typeof( DataGridContext ), - new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.NotDataBindable ) ); - - private static readonly DependencyProperty AutomationPeerProperty = AutomationPeerPropertyKey.DependencyProperty; - - internal DataGridContextAutomationPeer Peer - { - get - { - return this.GetValue( AutomationPeerProperty ) as DataGridContextAutomationPeer; - } - set - { - this.SetValue( AutomationPeerPropertyKey, value ); - } - } - - internal AutomationPeer PeerSource - { - get - { - if( m_parentItem == null ) - return FrameworkElementAutomationPeer.CreatePeerForElement( m_dataGridControl ); - - return this.Peer; - } - } - - internal void RaiseIsSelectedChangedAutomationEvent( DependencyObject container, bool isSelected ) - { - DataGridContextAutomationPeer peer = this.Peer; - - if( ( peer != null ) && ( peer.ItemPeers != null ) ) - { - object item = this.GetItemFromContainer( container ); - - if( item != null ) - { - Xceed.Wpf.DataGrid.Automation.DataGridItemAutomationPeer itemPeer = peer.ItemPeers[ item ] as Xceed.Wpf.DataGrid.Automation.DataGridItemAutomationPeer; - - if( itemPeer != null ) - itemPeer.RaiseAutomationIsSelectedChanged( isSelected ); - } - } - } - - #endregion Automation - //---------- SUB CLASSES ---------- #region DeferRestoreStateDisposable Private Class @@ -3920,8 +3634,8 @@ namespace Xceed.Wpf.DataGrid private void Dispose( bool disposing ) { - var wr = m_dataGridContext; - if( Interlocked.CompareExchange( ref m_dataGridContext, null, wr ) == null ) + var wr = Interlocked.Exchange( ref m_dataGridContext, null ); + if( wr == null ) return; var dataGridContext = ( DataGridContext )wr.Target; @@ -3966,10 +3680,7 @@ namespace Xceed.Wpf.DataGrid if( m_eventArgs != null ) { - if( m_eventArgs.Action != NotifyCollectionChangedAction.Reset ) - { - m_eventArgs = new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Reset ); - } + m_eventArgs = NotifyBatchCollectionChangedEventArgs.Combine( m_eventArgs, e ); } else { @@ -3988,8 +3699,8 @@ namespace Xceed.Wpf.DataGrid if( !disposing ) return; - var wr = m_dataGridContext; - if( Interlocked.CompareExchange( ref m_dataGridContext, null, wr ) == null ) + var wr = Interlocked.Exchange( ref m_dataGridContext, null ); + if( wr == null ) return; var eventArgs = m_eventArgs; @@ -4003,11 +3714,6 @@ namespace Xceed.Wpf.DataGrid dataGridContext.UpdateSelectionAfterSourceCollectionChanged( eventArgs ); } - ~DeferSelectionChangedOnItemsCollectionChangedDisposable() - { - this.Dispose( false ); - } - private WeakReference m_dataGridContext; private NotifyCollectionChangedEventArgs m_eventArgs; //null } @@ -4018,7 +3724,7 @@ namespace Xceed.Wpf.DataGrid private class ViewBindingPropertyDescriptor : PropertyDescriptor { - public ViewBindingPropertyDescriptor( DetailConfiguration detailConfig, DefaultDetailConfiguration defaultDetailConfig, Xceed.Wpf.DataGrid.Views.ViewBase view, DependencyProperty dp, ViewPropertyMode viewPropertyMode ) + public ViewBindingPropertyDescriptor( DetailConfiguration detailConfig, DefaultDetailConfiguration defaultDetailConfig, Views.ViewBase view, DependencyProperty dp, ViewPropertyMode viewPropertyMode ) : base( dp.Name, null ) { if( dp == null ) @@ -4081,7 +3787,7 @@ namespace Xceed.Wpf.DataGrid #region View Read-Only Property - public Xceed.Wpf.DataGrid.Views.ViewBase View + public Views.ViewBase View { get { @@ -4089,7 +3795,7 @@ namespace Xceed.Wpf.DataGrid } } - private Xceed.Wpf.DataGrid.Views.ViewBase m_view; + private Views.ViewBase m_view; #endregion @@ -4122,36 +3828,35 @@ namespace Xceed.Wpf.DataGrid public override object GetValue( object component ) { - object retval = null; - DependencyObject dependencyObject = component as DependencyObject; - if( dependencyObject != null ) + if( m_viewPropertyMode == ViewPropertyMode.Routed ) { - retval = dependencyObject.GetValue( m_dp ); - } + var source = ( DependencyObject )m_defaultDetailConfig ?? m_detailConfig; - //If there isa a DefaultDetailConfig, process it in precedence to the DetailConfig - if( m_defaultDetailConfig != null ) - { - //AND there is NO local value set on it. - object localValue = m_defaultDetailConfig.ReadLocalValue( m_dp ); - if( ( localValue == DependencyProperty.UnsetValue ) && ( this.ViewPropertyMode == ViewPropertyMode.Routed ) ) - { - //then use the View's Value. - retval = m_view.GetValue( m_dp ); - } - } - //If there isa a DetailConfig - else if( m_detailConfig != null ) - { - //AND there is NO local value set on it. - object localValue = m_detailConfig.ReadLocalValue( m_dp ); - if( ( localValue == DependencyProperty.UnsetValue ) && ( this.ViewPropertyMode == ViewPropertyMode.Routed ) ) + //If there is a DefaultDetailConfig, process it in precedence to the DetailConfig. + if( source != null ) { - //then use the View's Value. - retval = m_view.GetValue( m_dp ); + var valueSource = DependencyPropertyHelper.GetValueSource( source, m_dp ); + + switch( valueSource.BaseValueSource ) + { + // Pick the value on the view. + case BaseValueSource.Default: + case BaseValueSource.Inherited: + case BaseValueSource.Unknown: + return m_view.GetValue( m_dp ); + + // Pick the value on the source component itself. + default: + break; + } } } - return retval; + + var dependencyObject = component as DependencyObject; + if( dependencyObject != null ) + return dependencyObject.GetValue( m_dp ); + + return null; } public override bool IsReadOnly @@ -4177,13 +3882,11 @@ namespace Xceed.Wpf.DataGrid public override void SetValue( object component, object value ) { - DependencyObject dependencyObject = component as DependencyObject; - if( dependencyObject != null ) - { - dependencyObject.SetValue( m_dp, value ); - return; - } - throw new ArgumentException( "SetValue was called for an object which is not a DependencyObject.", component.ToString() ); + var dependencyObject = component as DependencyObject; + if( dependencyObject == null ) + throw new ArgumentException( "SetValue was called for an object which is not a DependencyObject.", component.ToString() ); + + dependencyObject.SetValue( m_dp, value ); } public override bool ShouldSerializeValue( object component ) @@ -4542,16 +4245,22 @@ namespace Xceed.Wpf.DataGrid protected override string GetColumnName( ColumnBase column ) { var dataGridContext = this.DataGridContext; - if( dataGridContext == null ) + if( ( dataGridContext == null ) || ( column == null ) ) return null; - var fieldNameMap = dataGridContext.ItemPropertyMap; - string fieldName; - - if( !fieldNameMap.TryGetItemPropertyName( column, out fieldName ) ) - return null; + var itemPropertyMap = dataGridContext.ItemPropertyMap; + if( ( itemPropertyMap != null ) && itemPropertyMap.IsMapping ) + { + string fieldName; + if( DataGridItemPropertyMapHelper.TryGetDetailColumnName( itemPropertyMap, column.FieldName, out fieldName ) ) + return fieldName; + } + else + { + return column.FieldName; + } - return fieldName; + return null; } protected override GroupDescription GetGroupDescription( ColumnBase column ) diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridControl.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridControl.cs index ffe2998b..50d4c3dd 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridControl.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridControl.cs @@ -22,6 +22,8 @@ using System.Collections.Specialized; using System.ComponentModel; using System.Data; using System.Diagnostics; +using System.Linq; +using System.Printing; using System.Security; using System.Security.Permissions; using System.Windows; @@ -35,10 +37,9 @@ using System.Windows.Media; using System.Windows.Threading; using Xceed.Utils.Wpf; using Xceed.Utils.Wpf.DragDrop; -using Xceed.Wpf.DataGrid.Automation; using Xceed.Wpf.DataGrid.Export; +using Xceed.Wpf.DataGrid.Utils; using Xceed.Wpf.DataGrid.Views; -using Xceed.Wpf.Toolkit.Core; namespace Xceed.Wpf.DataGrid { @@ -47,13 +48,17 @@ namespace Xceed.Wpf.DataGrid [StyleTypedProperty( Property = "CellErrorStyle", StyleTargetType = typeof( Cell ) )] public partial class DataGridControl : ItemsControl, INotifyPropertyChanged, IDocumentPaginatorSource, IWeakEventListener { + #region Static Fields + + internal static readonly string SelectionModeToUsePropertyName = PropertyHelper.GetPropertyName( ( DataGridControl d ) => d.SelectionModeToUse ); + + #endregion + static DataGridControl() { FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata( typeof( DataGridControl ), new FrameworkPropertyMetadata( TableflowView.GetDefaultStyleKey( typeof( TableflowView ), typeof( DataGridControl ) ) ) ); - ItemsControl.ItemsSourceProperty.OverrideMetadata( typeof( DataGridControl ), new FrameworkPropertyMetadata( null, - new CoerceValueCallback( DataGridControl.ItemsSourceCoerceCallback ) ) ); - + ItemsControl.ItemsSourceProperty.OverrideMetadata( typeof( DataGridControl ), new FrameworkPropertyMetadata( null, new CoerceValueCallback( DataGridControl.ItemsSourceCoerceCallback ) ) ); ItemsControl.GroupStyleSelectorProperty.OverrideMetadata( typeof( DataGridControl ), new FrameworkPropertyMetadata( new PropertyChangedCallback( OnGroupStyleSelectorChanged ) ) ); KeyboardNavigation.DirectionalNavigationProperty.OverrideMetadata( typeof( DataGridControl ), new FrameworkPropertyMetadata( KeyboardNavigationMode.Contained ) ); @@ -70,32 +75,24 @@ namespace Xceed.Wpf.DataGrid DataGridControl.DataGridContextProperty = DataGridControl.DataGridContextPropertyKey.DependencyProperty; DataGridControl.StatContextProperty = DataGridControl.StatContextPropertyKey.DependencyProperty; DataGridControl.GroupLevelDescriptionsProperty = DataGridControl.GroupLevelDescriptionsPropertyKey.DependencyProperty; - DataGridControl.DetailConfigurationsProperty = DataGridControl.DetailConfigurationsPropertyKey.DependencyProperty; DataGridControl.HasExpandedDetailsProperty = DataGridControl.HasExpandedDetailsPropertyKey.DependencyProperty; } public DataGridControl() { m_selectionChangerManager = new SelectionManager( this ); + m_columnManagerRowConfiguration = new ColumnManagerRowConfiguration(); this.SetValue( DataGridControl.ParentDataGridControlPropertyKey, this ); //set the FixedItem for the gridControl to NotSet, this is to prevent problems with nested DataGridControls DataGridControl.SetFixedItem( this, DataGridControl.NotSet ); - this.SetDetailConfigurations( new DetailConfigurationCollection( this, null ) ); - this.DetailConfigurations.CollectionChanged += this.OnDetailConfigurationsChanged; - this.CommandBindings.Add( new CommandBinding( DataGridCommands.ExpandGroup, this.OnExpandGroupExecuted, this.OnExpandGroupCanExecute ) ); - this.CommandBindings.Add( new CommandBinding( DataGridCommands.CollapseGroup, this.OnCollapseGroupExecuted, this.OnCollapseGroupCanExecute ) ); - this.CommandBindings.Add( new CommandBinding( DataGridCommands.ToggleGroupExpansion, this.OnToggleGroupExecuted, this.OnToggleGroupCanExecute ) ); - this.CommandBindings.Add( new CommandBinding( ApplicationCommands.SelectAll, this.OnSelectAllExecuted, this.OnSelectAllCanExecute ) ); - this.CommandBindings.Add( new CommandBinding( DataGridCommands.ClearFilter, this.OnClearFilterExecuted ) ); - // We keep a references to be able to remove the CommandBindings when they are not required (feature disabled) m_refreshCommandBinding = new CommandBinding( DataGridCommands.Refresh, this.OnRefreshExecuted, this.OnRefreshCanExecute ); this.CommandBindings.Add( m_refreshCommandBinding ); @@ -115,7 +112,7 @@ namespace Xceed.Wpf.DataGrid m_localDataGridContext = dataGridContext; //so that at least one DataGridContext is always current - dataGridContext.SetIsCurrentHelper( true ); + dataGridContext.SetIsCurrent( true ); this.SetCurrentDataGridContextHelper( dataGridContext ); this.SetValue( DataGridControl.ColumnsPropertyKey, dataGridContext.Columns ); @@ -138,75 +135,77 @@ namespace Xceed.Wpf.DataGrid } this.Loaded += new RoutedEventHandler( DataGridControl_Loaded ); - this.LayoutUpdated += new EventHandler( DataGridControl_LayoutUpdated ); } #region INITIALIZATION public override void BeginInit() { - m_beginInitCount++; + m_initCount++; + if( m_initCount != 1 ) + return; + + Debug.Assert( m_deferColumnsUpdate == null ); + m_deferColumnsUpdate = this.DataGridContext.DeferColumnsUpdate(); + Debug.Assert( m_deferColumnsUpdate != null ); - if( m_columnsInitDisposable == null ) + m_deferColumnsNotifications = this.Columns.DeferNotifications(); + + var dataGridCollectionViewBase = this.DataGridContext.Items as DataGridCollectionViewBase; + if( dataGridCollectionViewBase != null ) { - m_columnsInitDisposable = this.Columns.DeferColumnAdditionMessages(); + m_deferItemPropertiesUpdate = dataGridCollectionViewBase.ItemProperties.DeferCollectionChanged(); } - // The FrameworkElement implementation does not support nested BeginInit/EndInit - if( m_beginInitCount == 1 ) - base.BeginInit(); + base.BeginInit(); } public override void EndInit() { - if( m_beginInitCount > 0 ) - m_beginInitCount--; + m_initCount--; + if( m_initCount != 0 ) + return; - if( m_beginInitCount == 0 ) + // Set a view if none is set at this point. This will also make sure that eventual implicit style declarations for the default View in user applications will work. + if( this.View == null ) { - if( m_columnsInitDisposable != null ) - { - m_columnsInitDisposable.Dispose(); - m_columnsInitDisposable = null; - } + this.View = this.GetDefaultView() as UIViewBase; + } - // Reassociate the default view to the grid at the last moment so that eventual implicit style declarations for the default View in user applications will work. - if( this.View == null ) - { - this.OnViewChanged( null, this.GetDefaultView() ); - } + if( this.ItemsSourceChangedDelayed ) + { + this.ItemsSourceChangedDelayed = false; + this.ProcessDelayedItemsSourceChanged(); + } - if( this.ItemsSourceChangedDelayed ) - { - this.ItemsSourceChangedDelayed = false; - this.ProcessDelayedItemsSourceChanged(); - } + var dataGridContext = this.DataGridContext; + var columnManager = dataGridContext.ColumnManager; - //see if any of the GroupLevelDescriptions are matched to a column but aren't bound ( case 102437 ) and update then (bind them) if necessary - this.DataGridContext.SetupTitleBindingForGroupLevelDescriptions(); + columnManager.Initialize( this ); + columnManager.SetFixedColumnCount( TableView.GetFixedColumnCount( dataGridContext ) ); + //see if any of the GroupLevelDescriptions are matched to a column but aren't bound ( case 102437 ) and update then (bind them) if necessary + dataGridContext.SetupTitleBindingForGroupLevelDescriptions(); - // The FrameworkElement implementation does not support nested BeginInit/EndInit - base.EndInit(); + if( m_deferItemPropertiesUpdate != null ) + { + var collectionViewDisposable = m_deferItemPropertiesUpdate; + m_deferItemPropertiesUpdate = null; + collectionViewDisposable.Dispose(); } - } - private void DataGridControl_LayoutUpdated( object sender, EventArgs e ) - { - if( m_dataGridContextToRefreshPeerChlidren == null ) - return; - - foreach( DataGridContext dataGridContext in m_dataGridContextToRefreshPeerChlidren ) - { - DataGridContextAutomationPeer dataGridContextPeer = dataGridContext.Peer; + var columnsNotificationsDisposable = m_deferColumnsNotifications; + m_deferColumnsNotifications = null; + columnsNotificationsDisposable.Dispose(); - if( dataGridContextPeer == null ) - continue; + Debug.Assert( m_deferColumnsUpdate != null ); + var columnsUpdateDisposable = m_deferColumnsUpdate; + m_deferColumnsUpdate = null; + columnsUpdateDisposable.Dispose(); - dataGridContextPeer.ResetChildrenCache(); - } + m_customItemContainerGenerator.ForceReset = true; - m_dataGridContextToRefreshPeerChlidren = null; + base.EndInit(); } private void DataGridControl_Loaded( object sender, RoutedEventArgs e ) @@ -222,7 +221,7 @@ namespace Xceed.Wpf.DataGrid // to make the parent control load faster. A new layout pass // must be forced to render the datagrid content correctly. The layout // pass isn't inhibited when the grid is use for printing purpose. - if( ( this.DeferInitialLayoutPass ) && ( m_isFirstTimeLoaded ) && ( !this.IsPrinting ) ) + if( ( this.DeferInitialLayoutPass ) && ( m_isFirstTimeLoaded ) ) { m_isFirstTimeLoaded = false; @@ -263,26 +262,26 @@ namespace Xceed.Wpf.DataGrid private void UnhookToUnloaded() { - FrameworkElement parentWindow = ( m_parentWindow == null ) - ? this : m_parentWindow.Target as FrameworkElement; + var parentWindow = ( m_parentWindow != null ) ? m_parentWindow.Target as FrameworkElement : this; + if( parentWindow == null ) + return; FrameworkElementUnloadedEventManager.RemoveListener( parentWindow, this ); } - internal bool IsInInit - { - get - { - return ( m_columnsInitDisposable != null ); - } - } + private int m_initCount; //0 + private IDisposable m_deferColumnsUpdate; //null + private IDisposable m_deferColumnsNotifications; //null + private IDisposable m_deferItemPropertiesUpdate; //null - #endregion INITIALIZATION + #endregion #region ParentDataGridControl Attached Property internal static readonly DependencyPropertyKey ParentDataGridControlPropertyKey = DependencyProperty.RegisterAttachedReadOnly( - "ParentDataGridControl", typeof( DataGridControl ), typeof( DataGridControl ), + "ParentDataGridControl", + typeof( DataGridControl ), + typeof( DataGridControl ), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.Inherits ) ); public static readonly DependencyProperty ParentDataGridControlProperty; @@ -293,12 +292,14 @@ namespace Xceed.Wpf.DataGrid return ( DataGridControl )obj.GetValue( DataGridControl.ParentDataGridControlProperty ); } - #endregion ParentDataGridControl Attached Property + #endregion #region DataGridContext Attached Property internal static readonly DependencyPropertyKey DataGridContextPropertyKey = DependencyProperty.RegisterAttachedReadOnly( - "DataGridContext", typeof( DataGridContext ), typeof( DataGridControl ), + "DataGridContext", + typeof( DataGridContext ), + typeof( DataGridControl ), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.Inherits ) ); public static readonly DependencyProperty DataGridContextProperty; @@ -313,14 +314,16 @@ namespace Xceed.Wpf.DataGrid obj.SetValue( DataGridControl.DataGridContextPropertyKey, value ); } - private DataGridContext m_localDataGridContext; // = null + private readonly DataGridContext m_localDataGridContext; // = null - #endregion DataGridContext Attached Property + #endregion #region Container Attached Property private static readonly DependencyPropertyKey ContainerPropertyKey = DependencyProperty.RegisterAttachedReadOnly( - "Container", typeof( FrameworkElement ), typeof( DataGridControl ), + "Container", + typeof( FrameworkElement ), + typeof( DataGridControl ), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.Inherits ) ); public static readonly DependencyProperty ContainerProperty = DataGridControl.ContainerPropertyKey.DependencyProperty; @@ -332,7 +335,6 @@ namespace Xceed.Wpf.DataGrid internal static void SetContainer( DependencyObject obj, object value ) { - Debug.Assert( ( value == null ) || ( value is IDataGridItemContainer ) ); obj.SetValue( DataGridControl.ContainerPropertyKey, value ); } @@ -341,12 +343,14 @@ namespace Xceed.Wpf.DataGrid obj.ClearValue( DataGridControl.ContainerPropertyKey ); } - #endregion Container Attached Property + #endregion #region IsContainerPrepared Attached Property private static readonly DependencyPropertyKey IsContainerPreparedPropertyKey = DependencyProperty.RegisterAttachedReadOnly( - "IsContainerPrepared", typeof( bool ), typeof( DataGridControl ), + "IsContainerPrepared", + typeof( bool ), + typeof( DataGridControl ), new FrameworkPropertyMetadata( false ) ); private static readonly DependencyProperty IsContainerPreparedProperty = DataGridControl.IsContainerPreparedPropertyKey.DependencyProperty; @@ -366,12 +370,14 @@ namespace Xceed.Wpf.DataGrid obj.ClearValue( DataGridControl.IsContainerPreparedPropertyKey ); } - #endregion IsContainerPrepared Attached Property + #endregion #region StatContext Attached Property internal static readonly DependencyPropertyKey StatContextPropertyKey = DependencyProperty.RegisterAttachedReadOnly( - "StatContext", typeof( object ), typeof( DataGridControl ), + "StatContext", + typeof( object ), + typeof( DataGridControl ), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.Inherits ) ); public static readonly DependencyProperty StatContextProperty; @@ -386,24 +392,14 @@ namespace Xceed.Wpf.DataGrid obj.SetValue( DataGridControl.StatContextPropertyKey, statContext ); } - #endregion StatContext Attached Property - - #region HasDetails Read-Only Property - - public bool HasDetails - { - get - { - return ( this.DetailConfigurations.Count > 0 ); - } - } - #endregion #region HasExpandedDetails Attached Property internal static readonly DependencyPropertyKey HasExpandedDetailsPropertyKey = DependencyProperty.RegisterAttachedReadOnly( - "HasExpandedDetails", typeof( bool ), typeof( DataGridControl ), + "HasExpandedDetails", + typeof( bool ), + typeof( DataGridControl ), new FrameworkPropertyMetadata( false, FrameworkPropertyMetadataOptions.Inherits ) ); public static readonly DependencyProperty HasExpandedDetailsProperty; @@ -418,12 +414,15 @@ namespace Xceed.Wpf.DataGrid obj.SetValue( DataGridControl.HasExpandedDetailsPropertyKey, value ); } - #endregion HasDetails Attached Property + #endregion #region Columns Read-Only Property - private static readonly DependencyPropertyKey ColumnsPropertyKey = - DependencyProperty.RegisterReadOnly( "Columns", typeof( ColumnCollection ), typeof( DataGridControl ), new PropertyMetadata( null ) ); + private static readonly DependencyPropertyKey ColumnsPropertyKey = DependencyProperty.RegisterReadOnly( + "Columns", + typeof( ColumnCollection ), + typeof( DataGridControl ), + new PropertyMetadata( null ) ); public static readonly DependencyProperty ColumnsProperty; @@ -435,12 +434,14 @@ namespace Xceed.Wpf.DataGrid } } - #endregion Columns Read-Only Property + #endregion #region VisibleColumns Read-Only Property private static readonly DependencyPropertyKey VisibleColumnsPropertyKey = DependencyProperty.RegisterAttachedReadOnly( - "VisibleColumns", typeof( ReadOnlyObservableCollection ), typeof( DataGridControl ), + "VisibleColumns", + typeof( ReadOnlyObservableCollection ), + typeof( DataGridControl ), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.Inherits ) ); public static readonly DependencyProperty VisibleColumnsProperty; @@ -458,7 +459,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion VisibleColumns Read-Only Property + #endregion #region ColumnsByVisiblePosition Read-Only Property @@ -470,12 +471,14 @@ namespace Xceed.Wpf.DataGrid } } - #endregion ColumnsByVisiblePosition Read-Only Property + #endregion #region CellEditorDisplayConditions Property public static readonly DependencyProperty CellEditorDisplayConditionsProperty = DependencyProperty.RegisterAttached( - "CellEditorDisplayConditions", typeof( CellEditorDisplayConditions ), typeof( DataGridControl ), + "CellEditorDisplayConditions", + typeof( CellEditorDisplayConditions ), + typeof( DataGridControl ), new FrameworkPropertyMetadata( CellEditorDisplayConditions.None, FrameworkPropertyMetadataOptions.Inherits ) ); public CellEditorDisplayConditions CellEditorDisplayConditions @@ -490,7 +493,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion CellEditorDisplayConditions Property + #endregion #region DefaultCellEditors Property @@ -502,14 +505,16 @@ namespace Xceed.Wpf.DataGrid } } - private Dictionary m_defaultCellEditors = new Dictionary(); + private readonly Dictionary m_defaultCellEditors = new Dictionary(); - #endregion DefaultCellEditors Property + #endregion #region CellErrorStyle Property public static readonly DependencyProperty CellErrorStyleProperty = DependencyProperty.RegisterAttached( - "CellErrorStyle", typeof( Style ), typeof( DataGridControl ), + "CellErrorStyle", + typeof( Style ), + typeof( DataGridControl ), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.Inherits ) ); public Style CellErrorStyle @@ -525,15 +530,17 @@ namespace Xceed.Wpf.DataGrid } } - #endregion CellErrorStyle Property + #endregion #region HasValidationError Property - private static readonly DependencyPropertyKey HasValidationErrorPropertyKey = - DependencyProperty.RegisterReadOnly( "HasValidationError", typeof( bool ), typeof( DataGridControl ), new UIPropertyMetadata( false ) ); + private static readonly DependencyPropertyKey HasValidationErrorPropertyKey = DependencyProperty.RegisterReadOnly( + "HasValidationError", + typeof( bool ), + typeof( DataGridControl ), + new UIPropertyMetadata( false ) ); - public static readonly DependencyProperty HasValidationErrorProperty = - HasValidationErrorPropertyKey.DependencyProperty; + public static readonly DependencyProperty HasValidationErrorProperty = DataGridControl.HasValidationErrorPropertyKey.DependencyProperty; public bool HasValidationError { @@ -558,7 +565,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion HasValidationError Property + #endregion #region ValidationMode Property @@ -583,12 +590,15 @@ namespace Xceed.Wpf.DataGrid } } - #endregion ValidationMode Property + #endregion #region SelectedItems Read-Only Property - private static readonly DependencyPropertyKey SelectedItemsPropertyKey = - DependencyProperty.RegisterReadOnly( "SelectedItems", typeof( IList ), typeof( DataGridControl ), new PropertyMetadata( null ) ); + private static readonly DependencyPropertyKey SelectedItemsPropertyKey = DependencyProperty.RegisterReadOnly( + "SelectedItems", + typeof( IList ), + typeof( DataGridControl ), + new PropertyMetadata( null ) ); public static readonly DependencyProperty SelectedItemsProperty; @@ -600,12 +610,15 @@ namespace Xceed.Wpf.DataGrid } } - #endregion SelectedItems Read-Only Property + #endregion #region SelectedRanges Read-Only Property - private static readonly DependencyPropertyKey SelectedItemRangesPropertyKey = - DependencyProperty.RegisterReadOnly( "SelectedItemRanges", typeof( IList ), typeof( DataGridControl ), new PropertyMetadata( null ) ); + private static readonly DependencyPropertyKey SelectedItemRangesPropertyKey = DependencyProperty.RegisterReadOnly( + "SelectedItemRanges", + typeof( IList ), + typeof( DataGridControl ), + new PropertyMetadata( null ) ); public static readonly DependencyProperty SelectedItemRangesProperty; @@ -617,12 +630,15 @@ namespace Xceed.Wpf.DataGrid } } - #endregion SelectedItemRanges Read-Only Property + #endregion #region SelectedCellRanges Read-Only Property - private static readonly DependencyPropertyKey SelectedCellRangesPropertyKey = - DependencyProperty.RegisterReadOnly( "SelectedCellRanges", typeof( IList ), typeof( DataGridControl ), new PropertyMetadata( null ) ); + private static readonly DependencyPropertyKey SelectedCellRangesPropertyKey = DependencyProperty.RegisterReadOnly( + "SelectedCellRanges", + typeof( IList ), + typeof( DataGridControl ), + new PropertyMetadata( null ) ); public static readonly DependencyProperty SelectedCellRangesProperty; @@ -634,12 +650,15 @@ namespace Xceed.Wpf.DataGrid } } - #endregion SelectedCellRanges Read-Only Property + #endregion #region SelectedItem Property - public static readonly DependencyProperty SelectedItemProperty = - DependencyProperty.Register( "SelectedItem", typeof( object ), typeof( DataGridControl ), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback( OnSelectedItemChanged ), new CoerceValueCallback( OnCoerceSelectedItem ) ) ); + public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register( + "SelectedItem", + typeof( object ), + typeof( DataGridControl ), + new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback( DataGridControl.OnSelectedItemChanged ), new CoerceValueCallback( DataGridControl.OnCoerceSelectedItem ) ) ); public object SelectedItem { @@ -660,59 +679,59 @@ namespace Xceed.Wpf.DataGrid private static object OnCoerceSelectedItem( DependencyObject sender, object value ) { - DataGridControl dataGridControl = ( DataGridControl )sender; + var self = sender as DataGridControl; + if( self == null ) + return value; - if( ( value != null ) && ( !dataGridControl.m_skipCoerceSelectedItemCheck ) ) + if( ( value != null ) && ( !self.m_skipCoerceSelectedItemCheck ) ) { - if( !dataGridControl.Items.Contains( value ) ) + if( !self.Items.Contains( value ) ) { - dataGridControl.SelectedItemPropertyNeedCoerce = true; + self.SelectedItemPropertyNeedCoerce = true; return DependencyProperty.UnsetValue; } } - dataGridControl.SelectedItemPropertyNeedCoerce = false; + self.SelectedItemPropertyNeedCoerce = false; return value; } private static void OnSelectedItemChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - DataGridControl dataGrid = ( DataGridControl )sender; + var self = sender as DataGridControl; + if( ( self == null ) || self.m_selectionChangerManager.IsActive ) + return; - if( dataGrid != null ) + self.m_selectionChangerManager.Begin(); + + try { - if( !dataGrid.m_selectionChangerManager.IsActive ) + if( e.NewValue == null ) { - dataGrid.m_selectionChangerManager.Begin(); - - try - { - if( e.NewValue == null ) - { - dataGrid.m_selectionChangerManager.UnselectAll(); - } - else - { - dataGrid.m_selectionChangerManager.SelectJustThisItem( - dataGrid.DataGridContext, dataGrid.Items.IndexOf( e.NewValue ), e.NewValue ); - } - } - finally - { - dataGrid.m_selectionChangerManager.End( false, false, true ); - } + self.m_selectionChangerManager.UnselectAll(); } + else + { + self.m_selectionChangerManager.SelectJustThisItem( self.DataGridContext, self.Items.IndexOf( e.NewValue ), e.NewValue ); + } + } + finally + { + self.m_selectionChangerManager.End( false, true ); } } private bool m_skipCoerceSelectedItemCheck; - #endregion SelectedItem Property + #endregion #region SelectedIndex Property - public static readonly DependencyProperty SelectedIndexProperty = - DependencyProperty.Register( "SelectedIndex", typeof( int ), typeof( DataGridControl ), new FrameworkPropertyMetadata( -1, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback( OnSelectedIndexChanged ), new CoerceValueCallback( OnCoerceSelectedIndex ) ) ); + public static readonly DependencyProperty SelectedIndexProperty = DependencyProperty.Register( + "SelectedIndex", + typeof( int ), + typeof( DataGridControl ), + new FrameworkPropertyMetadata( -1, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback( DataGridControl.OnSelectedIndexChanged ), new CoerceValueCallback( DataGridControl.OnCoerceSelectedIndex ) ) ); public int SelectedIndex { @@ -728,55 +747,52 @@ namespace Xceed.Wpf.DataGrid private static object OnCoerceSelectedIndex( DependencyObject sender, object value ) { - DataGridControl dataGrid = sender as DataGridControl; + var self = sender as DataGridControl; + if( self == null ) + return value; - int newValue = ( int )value; + var newValue = ( int )value; - if( ( newValue < -1 ) || ( newValue >= dataGrid.Items.Count ) ) + if( ( newValue < -1 ) || ( newValue >= self.Items.Count ) ) { - dataGrid.SelectedIndexPropertyNeedCoerce = true; + self.SelectedIndexPropertyNeedCoerce = true; return DependencyProperty.UnsetValue; } - dataGrid.SelectedIndexPropertyNeedCoerce = false; + self.SelectedIndexPropertyNeedCoerce = false; return value; } private static void OnSelectedIndexChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - DataGridControl dataGrid = sender as DataGridControl; + var self = sender as DataGridControl; + if( ( self == null ) || self.m_selectionChangerManager.IsActive ) + return; - if( dataGrid != null ) - { - int newValue = ( int )e.NewValue; + var newValue = ( int )e.NewValue; - if( !dataGrid.m_selectionChangerManager.IsActive ) - { - dataGrid.m_selectionChangerManager.Begin(); + self.m_selectionChangerManager.Begin(); - try - { - if( ( newValue >= 0 ) && ( newValue < dataGrid.Items.Count ) ) - { - //affect the item as the new selection - dataGrid.m_selectionChangerManager.SelectJustThisItem( - dataGrid.DataGridContext, newValue, dataGrid.Items[ newValue ] ); - } - else - { - //clear the selection. - dataGrid.m_selectionChangerManager.UnselectAll(); - } - } - finally - { - dataGrid.m_selectionChangerManager.End( false, false, true ); - } + try + { + if( ( newValue >= 0 ) && ( newValue < self.Items.Count ) ) + { + //affect the item as the new selection + self.m_selectionChangerManager.SelectJustThisItem( self.DataGridContext, newValue, self.Items[ newValue ] ); + } + else + { + //clear the selection. + self.m_selectionChangerManager.UnselectAll(); } } + finally + { + self.m_selectionChangerManager.End( false, true ); + } } - #endregion SelectedIndex Property + #endregion #region GlobalSelectedItems Read-Only Property @@ -784,9 +800,9 @@ namespace Xceed.Wpf.DataGrid { get { - foreach( DataGridContext context in this.SelectedContexts ) + foreach( var context in this.SelectedContexts ) { - foreach( object selectedItem in context.SelectedItems ) + foreach( var selectedItem in context.SelectedItems ) { yield return selectedItem; } @@ -796,7 +812,7 @@ namespace Xceed.Wpf.DataGrid internal void NotifyGlobalSelectedItemsChanged() { - this.OnNotifyPropertyChanged( new PropertyChangedEventArgs( "GlobalSelectedItems" ) ); + this.OnPropertyChanged( "GlobalSelectedItems" ); } #endregion @@ -808,23 +824,26 @@ namespace Xceed.Wpf.DataGrid get { if( m_readOnlySelectedContexts == null ) + { m_readOnlySelectedContexts = new ReadOnlyCollection( m_selectedContexts ); + } return m_readOnlySelectedContexts; } } - private List m_selectedContexts = new List(); + private readonly List m_selectedContexts = new List(); private ReadOnlyCollection m_readOnlySelectedContexts; - #endregion SelectedContexts Read-Only Property + #endregion #region SelectionMode Property - public static readonly DependencyProperty SelectionModeProperty = - DependencyProperty.Register( "SelectionMode", typeof( SelectionMode ), typeof( DataGridControl ), - new UIPropertyMetadata( SelectionMode.Extended, - new PropertyChangedCallback( DataGridControl.OnSelectionModeChanged ) ) ); + public static readonly DependencyProperty SelectionModeProperty = DependencyProperty.Register( + "SelectionMode", + typeof( SelectionMode ), + typeof( DataGridControl ), + new UIPropertyMetadata( SelectionMode.Extended, new PropertyChangedCallback( DataGridControl.OnSelectionModeChanged ) ) ); public SelectionMode SelectionMode { @@ -848,17 +867,20 @@ namespace Xceed.Wpf.DataGrid private static void OnSelectionModeChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { + var self = sender as DataGridControl; + if( self == null ) + return; } - #endregion SelectionMode Property + #endregion #region SelectionUnit Property - public static readonly DependencyProperty SelectionUnitProperty = - DependencyProperty.Register( "SelectionUnit", typeof( SelectionUnit ), typeof( DataGridControl ), - new UIPropertyMetadata( SelectionUnit.Row, - new PropertyChangedCallback( DataGridControl.OnSelectionUnitChanged ), - new CoerceValueCallback( DataGridControl.SelectionUnitCoerceValueCallback ) ) ); + public static readonly DependencyProperty SelectionUnitProperty = DependencyProperty.Register( + "SelectionUnit", + typeof( SelectionUnit ), + typeof( DataGridControl ), + new UIPropertyMetadata( SelectionUnit.Row, new PropertyChangedCallback( DataGridControl.OnSelectionUnitChanged ) ) ); public SelectionUnit SelectionUnit { @@ -874,43 +896,37 @@ namespace Xceed.Wpf.DataGrid private static void OnSelectionUnitChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - DataGridControl dataGrid = ( DataGridControl )sender; + var self = sender as DataGridControl; + if( self == null ) + return; - if( dataGrid != null ) - { - SelectionUnit selectionUnit = ( SelectionUnit )e.NewValue; + var selectionUnit = ( SelectionUnit )e.NewValue; - dataGrid.m_selectionChangerManager.Begin(); + self.m_selectionChangerManager.Begin(); - try - { - switch( selectionUnit ) - { - case SelectionUnit.Row: - { - dataGrid.m_selectionChangerManager.UnselectAllCells(); - break; - } - case SelectionUnit.Cell: - { - dataGrid.m_selectionChangerManager.UnselectAllItems(); - break; - } - } - } - finally + try + { + switch( selectionUnit ) { - dataGrid.m_selectionChangerManager.End( false, false, true ); + case SelectionUnit.Row: + { + self.m_selectionChangerManager.UnselectAllCells(); + break; + } + case SelectionUnit.Cell: + { + self.m_selectionChangerManager.UnselectAllItems(); + break; + } } } + finally + { + self.m_selectionChangerManager.End( false, true ); + } } - private static object SelectionUnitCoerceValueCallback( DependencyObject sender, object value ) - { - return value; - } - - #endregion SelectionUnit Property + #endregion #region CurrentItem Property @@ -933,11 +949,11 @@ namespace Xceed.Wpf.DataGrid { get { - return ( !this.IsPrinting ) && ( this.SynchronizeCurrent ); + return ( this.SynchronizeCurrent ); } } - #endregion CurrentItem Property + #endregion #region CurrentColumn Property @@ -956,7 +972,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion CurrentColumn Property + #endregion #region CurrentContext Property @@ -974,11 +990,11 @@ namespace Xceed.Wpf.DataGrid { m_currentDataGridContext = value; - this.OnNotifyPropertyChanged( new PropertyChangedEventArgs( "CurrentContext" ) ); - this.OnNotifyPropertyChanged( new PropertyChangedEventArgs( "CurrentColumn" ) ); - this.OnNotifyPropertyChanged( new PropertyChangedEventArgs( "CurrentItem" ) ); - this.OnNotifyPropertyChanged( new PropertyChangedEventArgs( "GlobalCurrentItem" ) ); - this.OnNotifyPropertyChanged( new PropertyChangedEventArgs( "GlobalCurrentColumn" ) ); + this.OnPropertyChanged( "CurrentContext" ); + this.OnPropertyChanged( "CurrentColumn" ); + this.OnPropertyChanged( "CurrentItem" ); + this.OnPropertyChanged( "GlobalCurrentItem" ); + this.OnPropertyChanged( "GlobalCurrentColumn" ); } private DataGridContext m_currentDataGridContext; // = null @@ -1011,8 +1027,6 @@ namespace Xceed.Wpf.DataGrid #region DragDropAdornerDecorator Property - private AdornerDecorator m_dragDropAdornerDecorator; - internal AdornerDecorator DragDropAdornerDecorator { get @@ -1021,12 +1035,17 @@ namespace Xceed.Wpf.DataGrid } } + private AdornerDecorator m_dragDropAdornerDecorator; + #endregion #region AutoCreateColumns Property - public static readonly DependencyProperty AutoCreateColumnsProperty = - DependencyProperty.Register( "AutoCreateColumns", typeof( bool ), typeof( DataGridControl ), new UIPropertyMetadata( true ) ); + public static readonly DependencyProperty AutoCreateColumnsProperty = DependencyProperty.Register( + "AutoCreateColumns", + typeof( bool ), + typeof( DataGridControl ), + new UIPropertyMetadata( true ) ); public bool AutoCreateColumns { @@ -1040,31 +1059,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion AutoCreateColumns Property - - #region AutoCreateDetailConfigurations Property - - internal static readonly DependencyProperty AutoCreateDetailConfigurationsProperty = - DependencyProperty.Register( "AutoCreateDetailConfigurations", typeof( bool ), typeof( DataGridControl ), new UIPropertyMetadata( false, null, new CoerceValueCallback( DataGridControl.AutoCreateDetailConfigurationsCoerceValueCallback ) ) ); - - internal bool AutoCreateDetailConfigurations - { - get - { - return ( bool )this.GetValue( DataGridControl.AutoCreateDetailConfigurationsProperty ); - } - set - { - this.SetValue( DataGridControl.AutoCreateDetailConfigurationsProperty, value ); - } - } - - private static object AutoCreateDetailConfigurationsCoerceValueCallback( DependencyObject sender, object value ) - { - return value; - } - - #endregion AutoCreateColumns Property + #endregion #region AutoCreateForeignKeyConfigurations Property @@ -1090,39 +1085,22 @@ namespace Xceed.Wpf.DataGrid private static void OnAutoCreateForeignKeyConfigurationsChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - DataGridControl dataGridControl = sender as DataGridControl; + var self = sender as DataGridControl; + if( ( self == null ) || !self.AutoCreateForeignKeyConfigurations ) + return; - if( ( dataGridControl != null ) && ( dataGridControl.AutoCreateForeignKeyConfigurations ) ) - { - dataGridControl.SynchronizeForeignKeyConfigurations(); - } + self.SynchronizeForeignKeyConfigurations(); } #endregion - #region AutoRemoveColumnsAndDetailConfigurations Property - - public static readonly DependencyProperty AutoRemoveColumnsAndDetailConfigurationsProperty = - DependencyProperty.Register( "AutoRemoveColumnsAndDetailConfigurations", typeof( bool ), typeof( DataGridControl ), new UIPropertyMetadata( true ) ); - - public bool AutoRemoveColumnsAndDetailConfigurations - { - get - { - return ( bool )this.GetValue( DataGridControl.AutoRemoveColumnsAndDetailConfigurationsProperty ); - } - set - { - this.SetValue( DataGridControl.AutoRemoveColumnsAndDetailConfigurationsProperty, value ); - } - } - - #endregion AutoRemoveColumnsAndDetailConfigurations Property - #region HideSelection Property - public static readonly DependencyProperty HideSelectionProperty = - DependencyProperty.Register( "HideSelection", typeof( bool ), typeof( DataGridControl ), new UIPropertyMetadata( false ) ); + public static readonly DependencyProperty HideSelectionProperty = DependencyProperty.Register( + "HideSelection", + typeof( bool ), + typeof( DataGridControl ), + new UIPropertyMetadata( false ) ); public bool HideSelection { @@ -1136,12 +1114,14 @@ namespace Xceed.Wpf.DataGrid } } - #endregion HideSelection Property + #endregion #region ReadOnly Property public static readonly DependencyProperty ReadOnlyProperty = DependencyProperty.RegisterAttached( - "ReadOnly", typeof( bool ), typeof( DataGridControl ), + "ReadOnly", + typeof( bool ), + typeof( DataGridControl ), new FrameworkPropertyMetadata( false, FrameworkPropertyMetadataOptions.Inherits ) ); public bool ReadOnly @@ -1156,7 +1136,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion ReadOnly Property + #endregion #region AutoScrollCurrentItem Property @@ -1178,14 +1158,15 @@ namespace Xceed.Wpf.DataGrid } } - #endregion AutoScrollCurrentItem Property + #endregion #region EditTriggers Property public static readonly DependencyProperty EditTriggersProperty = DependencyProperty.RegisterAttached( - "EditTriggers", typeof( EditTriggers ), typeof( DataGridControl ), - new FrameworkPropertyMetadata( EditTriggers.BeginEditCommand | EditTriggers.ClickOnCurrentCell | EditTriggers.ActivationGesture, - FrameworkPropertyMetadataOptions.Inherits ) ); + "EditTriggers", + typeof( EditTriggers ), + typeof( DataGridControl ), + new FrameworkPropertyMetadata( EditTriggers.BeginEditCommand | EditTriggers.ClickOnCurrentCell | EditTriggers.ActivationGesture, FrameworkPropertyMetadataOptions.Inherits ) ); public EditTriggers EditTriggers { @@ -1199,12 +1180,10 @@ namespace Xceed.Wpf.DataGrid } } - #endregion EditTriggers Property + #endregion #region ScrollViewer Property - private ScrollViewer m_scrollViewer; - internal ScrollViewer ScrollViewer { get @@ -1213,6 +1192,8 @@ namespace Xceed.Wpf.DataGrid } } + private ScrollViewer m_scrollViewer; + #endregion #region ItemsHost Property @@ -1223,15 +1204,15 @@ namespace Xceed.Wpf.DataGrid { if( m_itemsHost == null ) { - ScrollViewer scrollViewer = this.ScrollViewer; + var scrollViewer = this.ScrollViewer; if( scrollViewer == null ) return null; //this can be either a ItemsPresenter (which implements IScrollInfo and reforwards it to the ItemsPanel instantiated from the //ItemsPanelTemplate or the DataGridItemsHost used for the Container Recycling. - FrameworkElement scrollViewerContent = null; + var scrollViewerContent = default( FrameworkElement ); - ItemsPresenter itemsPresenter = scrollViewer.Content as ItemsPresenter; + var itemsPresenter = scrollViewer.Content as ItemsPresenter; if( itemsPresenter != null ) { if( VisualTreeHelper.GetChildrenCount( itemsPresenter ) > 0 ) @@ -1278,12 +1259,10 @@ namespace Xceed.Wpf.DataGrid } } - #endregion ItemsPanel override + #endregion #region FixedHeadersHostPanel Property - private Panel m_fixedHeadersHostPanel; - internal Panel FixedHeadersHostPanel { get @@ -1292,22 +1271,24 @@ namespace Xceed.Wpf.DataGrid } } - private void SetFixedHeadersHostPanel( Panel fixedHeadersHostPanel ) + private void SetFixedHeadersHostPanel( Panel panel ) { - if( m_fixedHeadersHostPanel == fixedHeadersHostPanel ) + if( m_fixedHeadersHostPanel == panel ) return; - m_fixedHeadersHostPanel = fixedHeadersHostPanel; + m_fixedHeadersHostPanel = panel; if( m_fixedHeadersHostPanel != null ) + { DataGridControl.RefreshFixedHeaderFooter( this, m_fixedHeadersHostPanel, this.GetView().FixedHeaders ); + } } - #endregion FixedHeadersHostPanel Property + private Panel m_fixedHeadersHostPanel; - #region FixedFootersHostPanel Property + #endregion - private Panel m_fixedFootersHostPanel; + #region FixedFootersHostPanel Property internal Panel FixedFootersHostPanel { @@ -1317,23 +1298,30 @@ namespace Xceed.Wpf.DataGrid } } - private void SetFixedFootersHostPanel( Panel fixedFootersHostPanel ) + private void SetFixedFootersHostPanel( Panel panel ) { - if( m_fixedFootersHostPanel == fixedFootersHostPanel ) + if( m_fixedFootersHostPanel == panel ) return; - m_fixedFootersHostPanel = fixedFootersHostPanel; + m_fixedFootersHostPanel = panel; if( m_fixedFootersHostPanel != null ) + { DataGridControl.RefreshFixedHeaderFooter( this, m_fixedFootersHostPanel, this.GetView().FixedFooters ); + } } - #endregion FixedFootersHostPanel Property + private Panel m_fixedFootersHostPanel; + + #endregion #region IsFixedHeadersHost Attached Property public static readonly DependencyProperty IsFixedHeadersHostProperty = DependencyProperty.RegisterAttached( - "IsFixedHeadersHost", typeof( bool ), typeof( DataGridControl ), new UIPropertyMetadata( false, new PropertyChangedCallback( OnIsFixedHeadersHost_Changed ) ) ); + "IsFixedHeadersHost", + typeof( bool ), + typeof( DataGridControl ), + new UIPropertyMetadata( false, new PropertyChangedCallback( DataGridControl.OnIsFixedHeadersHost_Changed ) ) ); public static bool GetIsFixedHeadersHost( DependencyObject obj ) { @@ -1350,29 +1338,28 @@ namespace Xceed.Wpf.DataGrid if( !( bool )e.NewValue ) return; - Panel panel = sender as Panel; - + var panel = sender as Panel; if( panel == null ) return; - DataGridContext dataGridContext = DataGridControl.GetDataGridContext( sender ); - - DataGridControl grid = ( dataGridContext != null ) - ? dataGridContext.DataGridControl - : null; + var dataGridContext = DataGridControl.GetDataGridContext( sender ); + var dataGridControl = ( dataGridContext != null ) ? dataGridContext.DataGridControl : null; - if( grid != null ) + if( dataGridControl != null ) { - grid.SetFixedHeadersHostPanel( panel ); + dataGridControl.SetFixedHeadersHostPanel( panel ); } } - #endregion IsFixedHeadersHost Attached Property + #endregion #region IsFixedFootersHost Attached Property - public static readonly DependencyProperty IsFixedFootersHostProperty = - DependencyProperty.RegisterAttached( "IsFixedFootersHost", typeof( bool ), typeof( DataGridControl ), new UIPropertyMetadata( false, new PropertyChangedCallback( OnIsFixedFootersHost_Changed ) ) ); + public static readonly DependencyProperty IsFixedFootersHostProperty = DependencyProperty.RegisterAttached( + "IsFixedFootersHost", + typeof( bool ), + typeof( DataGridControl ), + new UIPropertyMetadata( false, new PropertyChangedCallback( DataGridControl.OnIsFixedFootersHost_Changed ) ) ); public static bool GetIsFixedFootersHost( DependencyObject obj ) { @@ -1389,29 +1376,28 @@ namespace Xceed.Wpf.DataGrid if( !( bool )e.NewValue ) return; - Panel panel = sender as Panel; - + var panel = sender as Panel; if( panel == null ) return; - DataGridContext dataGridContext = DataGridControl.GetDataGridContext( sender ); - - DataGridControl grid = ( dataGridContext != null ) - ? dataGridContext.DataGridControl - : null; + var dataGridContext = DataGridControl.GetDataGridContext( sender ); + var dataGridControl = ( dataGridContext != null ) ? dataGridContext.DataGridControl : null; - if( grid != null ) + if( dataGridControl != null ) { - grid.SetFixedFootersHostPanel( panel ); + dataGridControl.SetFixedFootersHostPanel( panel ); } } - #endregion IsFixedFootersHost Attached Property + #endregion #region ItemsPrimaryAxis Property - public static readonly DependencyProperty ItemsPrimaryAxisProperty = - DependencyProperty.Register( "ItemsPrimaryAxis", typeof( PrimaryAxis ), typeof( DataGridControl ), new UIPropertyMetadata( PrimaryAxis.Vertical ) ); + public static readonly DependencyProperty ItemsPrimaryAxisProperty = DependencyProperty.Register( + "ItemsPrimaryAxis", + typeof( PrimaryAxis ), + typeof( DataGridControl ), + new UIPropertyMetadata( PrimaryAxis.Vertical ) ); public PrimaryAxis ItemsPrimaryAxis { @@ -1425,22 +1411,22 @@ namespace Xceed.Wpf.DataGrid } } - #endregion ItemsPrimaryAxis Property + #endregion #region View Property public static readonly DependencyProperty ViewProperty = DependencyProperty.Register( "View", - typeof( Xceed.Wpf.DataGrid.Views.UIViewBase ), + typeof( UIViewBase ), typeof( DataGridControl ), new UIPropertyMetadata( null, new PropertyChangedCallback( DataGridControl.OnViewChanged ), new CoerceValueCallback( DataGridControl.ViewCoerceValueCallback ) ) ); [TypeConverter( typeof( Markup.ViewConverter ) )] - public Xceed.Wpf.DataGrid.Views.UIViewBase View + public UIViewBase View { get { - return ( Xceed.Wpf.DataGrid.Views.UIViewBase )this.GetValue( DataGridControl.ViewProperty ); + return ( UIViewBase )this.GetValue( DataGridControl.ViewProperty ); } set { @@ -1453,9 +1439,11 @@ namespace Xceed.Wpf.DataGrid private static object ViewCoerceValueCallback( DependencyObject sender, object value ) { - var view = value as Xceed.Wpf.DataGrid.Views.UIViewBase; - if( ( view == null ) && ( sender is DataGridControl ) ) - return ( ( DataGridControl )sender ).GetDefaultView(); + var view = value as UIViewBase; + var dataGridControl = sender as DataGridControl; + + if( ( view == null ) && ( dataGridControl != null ) ) + return dataGridControl.GetDefaultView(); if( view != null ) { @@ -1468,18 +1456,20 @@ namespace Xceed.Wpf.DataGrid private static void OnViewChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - DataGridControl grid = ( DataGridControl )sender; + var self = sender as DataGridControl; + if( self == null ) + return; - //for case 1044618: leave edition mode (cancel) when view changes - grid.CancelEdit(); + // Cannot stay in editing mode when the view is changed + self.CancelEdit(); - var oldView = ( Xceed.Wpf.DataGrid.Views.ViewBase )e.OldValue; - var newView = ( Xceed.Wpf.DataGrid.Views.ViewBase )e.NewValue; + var oldView = e.OldValue as Views.ViewBase; + var newView = e.NewValue as Views.ViewBase; - grid.OnViewChanged( oldView, newView ); + self.OnViewChanged( oldView, newView ); } - private void OnViewChanged( Xceed.Wpf.DataGrid.Views.ViewBase oldView, Xceed.Wpf.DataGrid.Views.ViewBase newView ) + private void OnViewChanged( Views.ViewBase oldView, Views.ViewBase newView ) { if( oldView != null ) { @@ -1518,7 +1508,6 @@ namespace Xceed.Wpf.DataGrid // as the old ones). So, we have to force the new templates. This is mainly to setup the new ViewBindings. this.ReapplyTemplate(); - if( this.ViewChanged != null ) { this.ViewChanged( this, EventArgs.Empty ); @@ -1534,14 +1523,17 @@ namespace Xceed.Wpf.DataGrid this.DelayBringIntoViewAndFocusCurrent( DispatcherPriority.Render, AutoScrollCurrentItemSourceTriggers.ViewChanged ); } - private Xceed.Wpf.DataGrid.Views.UIViewBase m_defaultView; + private UIViewBase m_defaultView; - #endregion View Property + #endregion #region GroupLevelDescriptions Read-Only Property - private static readonly DependencyPropertyKey GroupLevelDescriptionsPropertyKey = - DependencyProperty.RegisterReadOnly( "GroupLevelDescriptions", typeof( GroupLevelDescriptionCollection ), typeof( DataGridControl ), new PropertyMetadata( null ) ); + private static readonly DependencyPropertyKey GroupLevelDescriptionsPropertyKey = DependencyProperty.RegisterReadOnly( + "GroupLevelDescriptions", + typeof( GroupLevelDescriptionCollection ), + typeof( DataGridControl ), + new PropertyMetadata( null ) ); public static readonly DependencyProperty GroupLevelDescriptionsProperty; @@ -1553,34 +1545,14 @@ namespace Xceed.Wpf.DataGrid } } - #endregion GroupLevelDescriptions Read-Only Property - - #region DetailConfigurations Read-Only Property - - private static readonly DependencyPropertyKey DetailConfigurationsPropertyKey = - DependencyProperty.RegisterReadOnly( "DetailConfigurations", typeof( DetailConfigurationCollection ), typeof( DataGridControl ), new PropertyMetadata( null ) ); - - public static readonly DependencyProperty DetailConfigurationsProperty; - - internal DetailConfigurationCollection DetailConfigurations - { - get - { - return ( DetailConfigurationCollection )this.GetValue( DataGridControl.DetailConfigurationsProperty ); - } - } - - internal void SetDetailConfigurations( DetailConfigurationCollection value ) - { - this.SetValue( DataGridControl.DetailConfigurationsPropertyKey, value ); - } - - #endregion DetailConfigurations Read-Only Property + #endregion #region NavigationBehavior Property public static readonly DependencyProperty NavigationBehaviorProperty = DependencyProperty.RegisterAttached( - "NavigationBehavior", typeof( NavigationBehavior ), typeof( DataGridControl ), + "NavigationBehavior", + typeof( NavigationBehavior ), + typeof( DataGridControl ), new FrameworkPropertyMetadata( NavigationBehavior.CellOnly, FrameworkPropertyMetadataOptions.Inherits ) ); public NavigationBehavior NavigationBehavior @@ -1595,12 +1567,11 @@ namespace Xceed.Wpf.DataGrid } } - #endregion NavigationBehavior Property + #endregion #region PagingBehavior Property - public static readonly DependencyProperty PagingBehaviorProperty = - DependencyProperty.Register( + public static readonly DependencyProperty PagingBehaviorProperty = DependencyProperty.Register( "PagingBehavior", typeof( PagingBehavior ), typeof( DataGridControl ), @@ -1618,7 +1589,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion PagingBehavior Property + #endregion #region ItemScrollingBehavior Property @@ -1640,7 +1611,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion ItemScrollingBehavior Property + #endregion #region CurrentRowInEditionState Read-Only Property @@ -1652,7 +1623,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion CurrentRowInEditionState Read-Only Property + #endregion #region CurrentItemInEdition Read-Only Property @@ -1664,7 +1635,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion CurrentItemInEdition Read-Only Property + #endregion #region FixedItem Attached Property @@ -1672,7 +1643,9 @@ namespace Xceed.Wpf.DataGrid // The ownerType is set to FrameworkElement to make the inheritance works for all grid elements. private static readonly DependencyProperty FixedItemProperty = DependencyProperty.RegisterAttached( - "FixedItem", typeof( object ), typeof( DataGridControl ), + "FixedItem", + typeof( object ), + typeof( DataGridControl ), new FrameworkPropertyMetadata( DataGridControl.NotSet, FrameworkPropertyMetadataOptions.Inherits ) ); private static object GetFixedItem( DependencyObject obj ) @@ -1685,7 +1658,7 @@ namespace Xceed.Wpf.DataGrid obj.SetValue( DataGridControl.FixedItemProperty, value ); } - #endregion FixedItem Attached Property + #endregion #region Hidden Properties @@ -1754,7 +1727,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion Hidden Properties + #endregion #region ItemContainerGenerator Property @@ -1769,7 +1742,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion ItemContainerGenerator Property + #endregion #region CustomItemContainerGenerator Property @@ -1781,15 +1754,17 @@ namespace Xceed.Wpf.DataGrid } } - #endregion CustomItemContainerGenerator Property + #endregion #region IsBeingEdited Property - private static readonly DependencyPropertyKey IsBeingEditedPropertyKey = - DependencyProperty.RegisterReadOnly( "IsBeingEdited", typeof( bool ), typeof( DataGridControl ), new UIPropertyMetadata( false ) ); + private static readonly DependencyPropertyKey IsBeingEditedPropertyKey = DependencyProperty.RegisterReadOnly( + "IsBeingEdited", + typeof( bool ), + typeof( DataGridControl ), + new UIPropertyMetadata( false ) ); - public static readonly DependencyProperty IsBeingEditedProperty = - IsBeingEditedPropertyKey.DependencyProperty; + public static readonly DependencyProperty IsBeingEditedProperty = IsBeingEditedPropertyKey.DependencyProperty; public bool IsBeingEdited { @@ -1801,22 +1776,21 @@ namespace Xceed.Wpf.DataGrid private void UpdateIsBeingEdited() { - bool isBeingEdited = ( m_currentItemInEdition != null ); + var isBeingEdited = ( m_currentItemInEdition != null ); + if( isBeingEdited == this.IsBeingEdited ) + return; - if( isBeingEdited != this.IsBeingEdited ) + if( isBeingEdited ) { - if( isBeingEdited ) - { - this.SetValue( DataGridControl.IsBeingEditedPropertyKey, isBeingEdited ); - } - else - { - this.ClearValue( DataGridControl.IsBeingEditedPropertyKey ); - } + this.SetValue( DataGridControl.IsBeingEditedPropertyKey, isBeingEdited ); + } + else + { + this.ClearValue( DataGridControl.IsBeingEditedPropertyKey ); } } - #endregion IsBeingEdited Property + #endregion #region DataGridContext Read-Only Property @@ -1832,8 +1806,11 @@ namespace Xceed.Wpf.DataGrid #region GroupConfigurationSelector Property - public static readonly DependencyProperty GroupConfigurationSelectorProperty = - DependencyProperty.Register( "GroupConfigurationSelector", typeof( GroupConfigurationSelector ), typeof( DataGridControl ), new FrameworkPropertyMetadata( null, new PropertyChangedCallback( OnGroupConfigurationSelectorChanged ) ) ); + public static readonly DependencyProperty GroupConfigurationSelectorProperty = DependencyProperty.Register( + "GroupConfigurationSelector", + typeof( GroupConfigurationSelector ), + typeof( DataGridControl ), + new FrameworkPropertyMetadata( null, new PropertyChangedCallback( OnGroupConfigurationSelectorChanged ) ) ); public GroupConfigurationSelector GroupConfigurationSelector { @@ -1851,22 +1828,26 @@ namespace Xceed.Wpf.DataGrid private static void OnGroupConfigurationSelectorChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - DataGridControl dataGridControl = sender as DataGridControl; - if( dataGridControl != null ) - { - if( dataGridControl.GroupConfigurationSelectorChanged != null ) - { - dataGridControl.GroupConfigurationSelectorChanged( dataGridControl, EventArgs.Empty ); - } - } + var self = sender as DataGridControl; + if( self == null ) + return; + + var handler = self.GroupConfigurationSelectorChanged; + if( handler == null ) + return; + + handler.Invoke( self, EventArgs.Empty ); } - #endregion GroupConfigurationSelector Property + #endregion #region AllowDetailToggle Property - public static readonly DependencyProperty AllowDetailToggleProperty = - DependencyProperty.Register( "AllowDetailToggle", typeof( bool ), typeof( DataGridControl ), new FrameworkPropertyMetadata( true, new PropertyChangedCallback( OnAllowDetailToggleChanged ) ) ); + public static readonly DependencyProperty AllowDetailToggleProperty = DependencyProperty.Register( + "AllowDetailToggle", + typeof( bool ), + typeof( DataGridControl ), + new FrameworkPropertyMetadata( true, new PropertyChangedCallback( DataGridControl.OnAllowDetailToggleChanged ) ) ); public bool AllowDetailToggle { @@ -1884,22 +1865,26 @@ namespace Xceed.Wpf.DataGrid private static void OnAllowDetailToggleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - DataGridControl dataGridControl = sender as DataGridControl; - if( dataGridControl != null ) - { - if( dataGridControl.AllowDetailToggleChanged != null ) - { - dataGridControl.AllowDetailToggleChanged( dataGridControl, EventArgs.Empty ); - } - } + var self = sender as DataGridControl; + if( self == null ) + return; + + var handler = self.AllowDetailToggleChanged; + if( handler == null ) + return; + + handler.Invoke( self, EventArgs.Empty ); } - #endregion AllowDetailToggle Property + #endregion #region DefaultDetailConfiguration Property - public static readonly DependencyProperty DefaultDetailConfigurationProperty = - DependencyProperty.Register( "DefaultDetailConfiguration", typeof( DefaultDetailConfiguration ), typeof( DataGridControl ), new FrameworkPropertyMetadata( null ) ); + public static readonly DependencyProperty DefaultDetailConfigurationProperty = DependencyProperty.Register( + "DefaultDetailConfiguration", + typeof( DefaultDetailConfiguration ), + typeof( DataGridControl ), + new FrameworkPropertyMetadata( null ) ); public DefaultDetailConfiguration DefaultDetailConfiguration { @@ -1913,12 +1898,15 @@ namespace Xceed.Wpf.DataGrid } } - #endregion DefaultDetailConfiguration Property + #endregion #region DefaultGroupConfiguration Property - public static readonly DependencyProperty DefaultGroupConfigurationProperty = - DependencyProperty.Register( "DefaultGroupConfiguration", typeof( GroupConfiguration ), typeof( DataGridControl ), new FrameworkPropertyMetadata( null ) ); + public static readonly DependencyProperty DefaultGroupConfigurationProperty = DependencyProperty.Register( + "DefaultGroupConfiguration", + typeof( GroupConfiguration ), + typeof( DataGridControl ), + new FrameworkPropertyMetadata( null ) ); public GroupConfiguration DefaultGroupConfiguration { @@ -1932,12 +1920,15 @@ namespace Xceed.Wpf.DataGrid } } - #endregion DefaultGroupConfiguration Property + #endregion #region ContainerGroupConfiguration Attached Property - internal static readonly DependencyProperty ContainerGroupConfigurationProperty = - DependencyProperty.RegisterAttached( "ContainerGroupConfiguration", typeof( GroupConfiguration ), typeof( DataGridControl ), new UIPropertyMetadata( null ) ); + internal static readonly DependencyProperty ContainerGroupConfigurationProperty = DependencyProperty.RegisterAttached( + "ContainerGroupConfiguration", + typeof( GroupConfiguration ), + typeof( DataGridControl ), + new UIPropertyMetadata( null ) ); internal static GroupConfiguration GetContainerGroupConfiguration( DependencyObject obj ) { @@ -1949,7 +1940,7 @@ namespace Xceed.Wpf.DataGrid obj.SetValue( DataGridControl.ContainerGroupConfigurationProperty, value ); } - #endregion ContainerGroupConfiguration Attached Property + #endregion #region ItemsSourceName Property @@ -1964,8 +1955,12 @@ namespace Xceed.Wpf.DataGrid } set { + if( value == m_itemsSourceName ) + return; + m_itemsSourceName = value; - this.OnNotifyPropertyChanged( new PropertyChangedEventArgs( "ItemsSourceName" ) ); + + this.OnPropertyChanged( "ItemsSourceName" ); } } @@ -1976,8 +1971,11 @@ namespace Xceed.Wpf.DataGrid #region ItemsSourceNameTemplate Property - public static readonly DependencyProperty ItemsSourceNameTemplateProperty = - DependencyProperty.Register( "ItemsSourceNameTemplate", typeof( DataTemplate ), typeof( DataGridControl ), new UIPropertyMetadata( null ) ); + public static readonly DependencyProperty ItemsSourceNameTemplateProperty = DependencyProperty.Register( + "ItemsSourceNameTemplate", + typeof( DataTemplate ), + typeof( DataGridControl ), + new UIPropertyMetadata( null ) ); public DataTemplate ItemsSourceNameTemplate { @@ -1991,31 +1989,33 @@ namespace Xceed.Wpf.DataGrid } } - #endregion ItemsSourceNameTemplate Property + #endregion #region UpdateSourceTrigger Property - public static readonly DependencyProperty UpdateSourceTriggerProperty = - DependencyProperty.Register( "UpdateSourceTrigger", typeof( DataGridUpdateSourceTrigger ), typeof( DataGridControl ), new UIPropertyMetadata( DataGridUpdateSourceTrigger.RowEndingEdit ) ); + public static readonly DependencyProperty UpdateSourceTriggerProperty = DependencyProperty.Register( + "UpdateSourceTrigger", + typeof( DataGridUpdateSourceTrigger ), + typeof( DataGridControl ), + new UIPropertyMetadata( DataGridUpdateSourceTrigger.RowEndingEdit ) ); public DataGridUpdateSourceTrigger UpdateSourceTrigger { get { - return ( DataGridUpdateSourceTrigger )GetValue( UpdateSourceTriggerProperty ); + return ( DataGridUpdateSourceTrigger )this.GetValue( DataGridControl.UpdateSourceTriggerProperty ); } set { - SetValue( UpdateSourceTriggerProperty, value ); + this.SetValue( DataGridControl.UpdateSourceTriggerProperty, value ); } } - #endregion UpdateSourceTrigger Property + #endregion #region ForceGeneratorReset Property - // This property is used to avoid a reset when Column Virtualization is - // on and all Row instances are using FixedCellPanel as PART_CellsHost + // This property is used to avoid a reset when Column Virtualization is on and all Row instances are using FixedCellPanel as PART_CellsHost internal bool ForceGeneratorReset { get @@ -2038,7 +2038,6 @@ namespace Xceed.Wpf.DataGrid { get { - if( m_clipboardExporters == null ) { m_clipboardExporters = new Dictionary(); @@ -2056,8 +2055,13 @@ namespace Xceed.Wpf.DataGrid csvClipboardExporter.FormatSettings.Separator = '\t'; csvClipboardExporter.FormatSettings.TextQualifier = '"'; m_clipboardExporters.Add( DataFormats.Text, csvClipboardExporter ); - } + // Configure HTML exporter + m_clipboardExporters.Add( DataFormats.Html, new HtmlClipboardExporter() ); + + // Configure Unicode ClipboardExporter + m_clipboardExporters.Add( DataFormats.UnicodeText, new UnicodeCsvClipboardExporter() ); + } } return m_clipboardExporters; @@ -2070,8 +2074,11 @@ namespace Xceed.Wpf.DataGrid #region IsDeleteCommandEnabled Property - public static readonly DependencyProperty IsDeleteCommandEnabledProperty = - DependencyProperty.Register( "IsDeleteCommandEnabled", typeof( bool ), typeof( DataGridControl ), new FrameworkPropertyMetadata( false, new PropertyChangedCallback( DataGridControl.OnIsDeleteCommandEnabledChanged ) ) ); + public static readonly DependencyProperty IsDeleteCommandEnabledProperty = DependencyProperty.Register( + "IsDeleteCommandEnabled", + typeof( bool ), + typeof( DataGridControl ), + new FrameworkPropertyMetadata( false, new PropertyChangedCallback( DataGridControl.OnIsDeleteCommandEnabledChanged ) ) ); public bool IsDeleteCommandEnabled { @@ -2085,28 +2092,29 @@ namespace Xceed.Wpf.DataGrid } } - private static void OnIsDeleteCommandEnabledChanged( DependencyObject obj, DependencyPropertyChangedEventArgs e ) + private static void OnIsDeleteCommandEnabledChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - DataGridControl dataGridControl = obj as DataGridControl; - - if( dataGridControl == null ) + var self = sender as DataGridControl; + if( self == null ) return; // On keep the command binding active if it is required if( ( bool )e.NewValue ) { - if( !dataGridControl.CommandBindings.Contains( dataGridControl.m_deleteCommandBinding ) ) - dataGridControl.CommandBindings.Add( dataGridControl.m_deleteCommandBinding ); + if( !self.CommandBindings.Contains( self.m_deleteCommandBinding ) ) + { + self.CommandBindings.Add( self.m_deleteCommandBinding ); + } } else { - dataGridControl.CommandBindings.Remove( dataGridControl.m_deleteCommandBinding ); + self.CommandBindings.Remove( self.m_deleteCommandBinding ); } CommandManager.InvalidateRequerySuggested(); } - #endregion IsDeleteCommandEnabled Property + #endregion #region IsCopyCommandEnabled Property @@ -2128,22 +2136,23 @@ namespace Xceed.Wpf.DataGrid } } - private static void OnIsCopyCommandEnabledChanged( DependencyObject o, DependencyPropertyChangedEventArgs e ) + private static void OnIsCopyCommandEnabledChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - DataGridControl dataGridControl = o as DataGridControl; - - if( dataGridControl == null ) + var self = sender as DataGridControl; + if( self == null ) return; // On keep the command binding active if it is required if( ( bool )e.NewValue ) { - if( !dataGridControl.CommandBindings.Contains( dataGridControl.m_copyCommandBinding ) ) - dataGridControl.CommandBindings.Add( dataGridControl.m_copyCommandBinding ); + if( !self.CommandBindings.Contains( self.m_copyCommandBinding ) ) + { + self.CommandBindings.Add( self.m_copyCommandBinding ); + } } else { - dataGridControl.CommandBindings.Remove( dataGridControl.m_copyCommandBinding ); + self.CommandBindings.Remove( self.m_copyCommandBinding ); } CommandManager.InvalidateRequerySuggested(); @@ -2153,8 +2162,10 @@ namespace Xceed.Wpf.DataGrid #region IsRefreshCommandEnabled Property - public static readonly DependencyProperty IsRefreshCommandEnabledProperty = - DependencyProperty.Register( "IsRefreshCommandEnabled", typeof( bool ), typeof( DataGridControl ), + public static readonly DependencyProperty IsRefreshCommandEnabledProperty = DependencyProperty.Register( + "IsRefreshCommandEnabled", + typeof( bool ), + typeof( DataGridControl ), new FrameworkPropertyMetadata( true, new PropertyChangedCallback( DataGridControl.OnIsRefreshCommandEnabledChanged ) ) ); public bool IsRefreshCommandEnabled @@ -2169,34 +2180,37 @@ namespace Xceed.Wpf.DataGrid } } - private static void OnIsRefreshCommandEnabledChanged( DependencyObject obj, DependencyPropertyChangedEventArgs e ) + private static void OnIsRefreshCommandEnabledChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - DataGridControl dataGridControl = obj as DataGridControl; - - if( dataGridControl == null ) + var self = sender as DataGridControl; + if( self == null ) return; // On keep the command binding active if it is required if( ( bool )e.NewValue ) { - if( !dataGridControl.CommandBindings.Contains( dataGridControl.m_refreshCommandBinding ) ) - dataGridControl.CommandBindings.Add( dataGridControl.m_refreshCommandBinding ); + if( !self.CommandBindings.Contains( self.m_refreshCommandBinding ) ) + { + self.CommandBindings.Add( self.m_refreshCommandBinding ); + } } else { - dataGridControl.CommandBindings.Remove( dataGridControl.m_refreshCommandBinding ); + self.CommandBindings.Remove( self.m_refreshCommandBinding ); } CommandManager.InvalidateRequerySuggested(); } - #endregion IsRefreshCommandEnabled Property + #endregion #region MaxSortLevels Property - public static readonly DependencyProperty MaxSortLevelsProperty = - DependencyProperty.Register( "MaxSortLevels", typeof( int ), typeof( DataGridControl ), - new FrameworkPropertyMetadata( -1, new PropertyChangedCallback( DataGridControl.OnMaxSortLevelsChanged ) ) ); + public static readonly DependencyProperty MaxSortLevelsProperty = DependencyProperty.Register( + "MaxSortLevels", + typeof( int ), + typeof( DataGridControl ), + new FrameworkPropertyMetadata( -1, new PropertyChangedCallback( DataGridControl.OnMaxSortLevelsChanged ) ) ); public int MaxSortLevels { @@ -2214,23 +2228,26 @@ namespace Xceed.Wpf.DataGrid private static void OnMaxSortLevelsChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - DataGridControl dataGridControl = sender as DataGridControl; - if( dataGridControl != null ) - { - if( dataGridControl.MaxSortLevelsChanged != null ) - { - dataGridControl.MaxSortLevelsChanged( dataGridControl, EventArgs.Empty ); - } - } + var self = sender as DataGridControl; + if( self == null ) + return; + + var handler = self.MaxSortLevelsChanged; + if( handler == null ) + return; + + handler.Invoke( self, EventArgs.Empty ); } - #endregion MaxSortLevels Property + #endregion #region MaxGroupLevels Property - public static readonly DependencyProperty MaxGroupLevelsProperty = - DependencyProperty.Register( "MaxGroupLevels", typeof( int ), typeof( DataGridControl ), - new FrameworkPropertyMetadata( -1, new PropertyChangedCallback( DataGridControl.OnMaxGroupLevelsChanged ) ) ); + public static readonly DependencyProperty MaxGroupLevelsProperty = DependencyProperty.Register( + "MaxGroupLevels", + typeof( int ), + typeof( DataGridControl ), + new FrameworkPropertyMetadata( -1, new PropertyChangedCallback( DataGridControl.OnMaxGroupLevelsChanged ) ) ); public int MaxGroupLevels { @@ -2248,63 +2265,73 @@ namespace Xceed.Wpf.DataGrid private static void OnMaxGroupLevelsChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - DataGridControl dataGridControl = sender as DataGridControl; - if( dataGridControl != null ) - { - if( dataGridControl.MaxGroupLevelsChanged != null ) - { - dataGridControl.MaxGroupLevelsChanged( dataGridControl, EventArgs.Empty ); - } - } + var self = sender as DataGridControl; + if( self == null ) + return; + + var handler = self.MaxGroupLevelsChanged; + if( handler == null ) + return; + + handler.Invoke( self, EventArgs.Empty ); } - #endregion MaxGroupLevels Property + #endregion #region SynchronizeSelectionWithCurrent Property - public static readonly DependencyProperty SynchronizeSelectionWithCurrentProperty = - DependencyProperty.Register( "SynchronizeSelectionWithCurrent", typeof( bool ), typeof( DataGridControl ), new UIPropertyMetadata( false ) ); + public static readonly DependencyProperty SynchronizeSelectionWithCurrentProperty = DependencyProperty.Register( + "SynchronizeSelectionWithCurrent", + typeof( bool ), + typeof( DataGridControl ), + new UIPropertyMetadata( false ) ); public bool SynchronizeSelectionWithCurrent { get { - return ( bool )GetValue( DataGridControl.SynchronizeSelectionWithCurrentProperty ); + return ( bool )this.GetValue( DataGridControl.SynchronizeSelectionWithCurrentProperty ); } set { - SetValue( DataGridControl.SynchronizeSelectionWithCurrentProperty, value ); + this.SetValue( DataGridControl.SynchronizeSelectionWithCurrentProperty, value ); } } - #endregion SynchronizeSelectionWithCurrent Property + #endregion #region SynchronizeCurrent Property - public static readonly DependencyProperty SynchronizeCurrentProperty = - DependencyProperty.Register( "SynchronizeCurrent", typeof( bool ), typeof( DataGridControl ), new UIPropertyMetadata( true ) ); + public static readonly DependencyProperty SynchronizeCurrentProperty = DependencyProperty.Register( + "SynchronizeCurrent", + typeof( bool ), + typeof( DataGridControl ), + new UIPropertyMetadata( true ) ); public bool SynchronizeCurrent { get { - return ( bool )GetValue( DataGridControl.SynchronizeCurrentProperty ); + return ( bool )this.GetValue( DataGridControl.SynchronizeCurrentProperty ); } set { - SetValue( DataGridControl.SynchronizeCurrentProperty, value ); + this.SetValue( DataGridControl.SynchronizeCurrentProperty, value ); } } - #endregion SynchronizeCurrent Property + #endregion #region PreserveExtendedSelection Property [Obsolete( "The PreserveExtendedSelection dependency property is obsolete.", false )] [Browsable( false )] [EditorBrowsable( EditorBrowsableState.Never )] - public static readonly DependencyProperty PreserveExtendedSelectionProperty = - DependencyProperty.Register( "PreserveExtendedSelection", typeof( bool ), typeof( DataGridControl ), new UIPropertyMetadata( false ) ); + public static readonly DependencyProperty PreserveExtendedSelectionProperty = DependencyProperty.Register( + "PreserveExtendedSelection", + typeof( bool ), + typeof( DataGridControl ), + new UIPropertyMetadata( false ) ); [Obsolete( "The PreserveExtendedSelection property is obsolete.", false )] [Browsable( false )] @@ -2314,26 +2341,29 @@ namespace Xceed.Wpf.DataGrid get { #pragma warning disable 618 - return ( bool )GetValue( DataGridControl.PreserveExtendedSelectionProperty ); + return ( bool )this.GetValue( DataGridControl.PreserveExtendedSelectionProperty ); #pragma warning restore 618 } set { #pragma warning disable 618 - SetValue( DataGridControl.PreserveExtendedSelectionProperty, value ); + this.SetValue( DataGridControl.PreserveExtendedSelectionProperty, value ); #pragma warning restore 618 } } - #endregion PreserveExtendedSelection + #endregion #region PreserveSelectionWhenEnteringEdit Property [Obsolete( "The PreserveSelectionWhenEnteringEdit dependency property is obsolete.", false )] [Browsable( false )] [EditorBrowsable( EditorBrowsableState.Never )] - public static readonly DependencyProperty PreserveSelectionWhenEnteringEditProperty = - DependencyProperty.Register( "PreserveSelectionWhenEnteringEdit", typeof( bool ), typeof( DataGridControl ), new UIPropertyMetadata( false ) ); + public static readonly DependencyProperty PreserveSelectionWhenEnteringEditProperty = DependencyProperty.Register( + "PreserveSelectionWhenEnteringEdit", + typeof( bool ), + typeof( DataGridControl ), + new UIPropertyMetadata( false ) ); [Obsolete( "The PreserveSelectionWhenEnteringEdit property is obsolete.", false )] [Browsable( false )] @@ -2343,18 +2373,18 @@ namespace Xceed.Wpf.DataGrid get { #pragma warning disable 618 - return ( bool )GetValue( DataGridControl.PreserveSelectionWhenEnteringEditProperty ); + return ( bool )this.GetValue( DataGridControl.PreserveSelectionWhenEnteringEditProperty ); #pragma warning restore 618 } set { #pragma warning disable 618 - SetValue( DataGridControl.PreserveSelectionWhenEnteringEditProperty, value ); + this.SetValue( DataGridControl.PreserveSelectionWhenEnteringEditProperty, value ); #pragma warning restore 618 } } - #endregion PreserveSelectionWhenEnteringEdit + #endregion #region ItemsSourceChangedDelayed Private Property @@ -2404,6 +2434,20 @@ namespace Xceed.Wpf.DataGrid #endregion + #region ColumnManagerRowConfiguration Internal Property + + internal ColumnManagerRowConfiguration ColumnManagerRowConfiguration + { + get + { + return m_columnManagerRowConfiguration; + } + } + + private readonly ColumnManagerRowConfiguration m_columnManagerRowConfiguration; + + #endregion + #region IsBoundToDataGridVirtualizingCollectionViewBase Private Property private bool IsBoundToDataGridVirtualizingCollectionViewBase @@ -2464,6 +2508,18 @@ namespace Xceed.Wpf.DataGrid #endregion + #region MouseDownSelectionRangePoint Property + + internal SelectionRangePoint MouseDownSelectionRangePoint + { + get + { + return m_mouseDownSelectionRangePoint; + } + } + + #endregion + #region HandlesScrolling Property protected override bool HandlesScrolling @@ -2478,8 +2534,11 @@ namespace Xceed.Wpf.DataGrid #region ConnectionState ReadOnly Dependency Property - private static readonly DependencyPropertyKey ConnectionStatePropertyKey = - DependencyProperty.RegisterReadOnly( "ConnectionState", typeof( DataGridConnectionState ), typeof( DataGridControl ), new UIPropertyMetadata( DataGridConnectionState.Idle ) ); + private static readonly DependencyPropertyKey ConnectionStatePropertyKey = DependencyProperty.RegisterReadOnly( + "ConnectionState", + typeof( DataGridConnectionState ), + typeof( DataGridControl ), + new UIPropertyMetadata( DataGridConnectionState.Idle ) ); public static readonly DependencyProperty ConnectionStateProperty = DataGridControl.ConnectionStatePropertyKey.DependencyProperty; @@ -2503,12 +2562,15 @@ namespace Xceed.Wpf.DataGrid } } - #endregion ConnectionState ReadOnly Dependency Property + #endregion #region ConnectionError ReadOnly Dependency Property - private static readonly DependencyPropertyKey ConnectionErrorPropertyKey = - DependencyProperty.RegisterReadOnly( "ConnectionError", typeof( object ), typeof( DataGridControl ), new UIPropertyMetadata( null ) ); + private static readonly DependencyPropertyKey ConnectionErrorPropertyKey = DependencyProperty.RegisterReadOnly( + "ConnectionError", + typeof( object ), + typeof( DataGridControl ), + new UIPropertyMetadata( null ) ); public static readonly DependencyProperty ConnectionErrorProperty = DataGridControl.ConnectionErrorPropertyKey.DependencyProperty; @@ -2532,7 +2594,7 @@ namespace Xceed.Wpf.DataGrid } } - #endregion ConnectionError ReadOnly Dependency Property + #endregion #region DeferInitialLayoutPass Property @@ -2556,47 +2618,70 @@ namespace Xceed.Wpf.DataGrid #endregion - #region AreDetailsFlatten Internal Property + #region ItemsSourcePropertyDescriptions Internal Property - internal bool AreDetailsFlatten + internal PropertyDescriptionRouteDictionary ItemsSourcePropertyDescriptions { get { - var currentView = this.GetView( false ); - if( currentView == null ) - return false; + return m_itemsSourcePropertyDescriptions; + } + } - var attributes = currentView.GetType().GetCustomAttributes( typeof( MasterDetailLayoutAttribute ), true ); - if( ( attributes == null ) || ( attributes.Length == 0 ) ) - return false; + private readonly PropertyDescriptionRouteDictionary m_itemsSourcePropertyDescriptions = new PropertyDescriptionRouteDictionary(); + + #endregion - var attribute = ( MasterDetailLayoutAttribute )attributes[ 0 ]; + #region ItemPropertyMap Internal Property - return ( attribute.MasterDetailLayoutMode == MasterDetailLayoutMode.Flatten ); + internal DataGridItemPropertyMap ItemPropertyMap + { + get + { + return m_itemPropertyMap; } } + private readonly DataGridItemPropertyMap m_itemPropertyMap = new DataGridItemPropertyMap(); + #endregion - #region GridUniqueName "conditional" Property + #region AreDetailsFlatten Internal Property - private string GridUniqueName + internal bool AreDetailsFlatten { get { - return m_gridUniqueName; - } - set - { - if( value != m_gridUniqueName ) + var view = this.GetView(); + if( view == null ) + return false; + + var viewType = view.GetType(); + if( viewType != m_areDetailsFlattenCache.Key ) { - m_gridUniqueName = value; - m_customItemContainerGenerator.ResetLog( value ); + var attributes = viewType.GetCustomAttributes( typeof( MasterDetailLayoutAttribute ), true ); + var flatten = ( attributes != null ) + && ( attributes.Length > 0 ) + && ( ( ( MasterDetailLayoutAttribute )attributes[ 0 ] ).MasterDetailLayoutMode == MasterDetailLayoutMode.Flatten ); + + m_areDetailsFlattenCache = new KeyValuePair( viewType, flatten ); } + + return m_areDetailsFlattenCache.Value; } } - private string m_gridUniqueName; + private KeyValuePair m_areDetailsFlattenCache; + + #endregion + + #region GridUniqueName Property + + internal string GridUniqueName + { + get; + set; + } #endregion @@ -2606,24 +2691,28 @@ namespace Xceed.Wpf.DataGrid #endregion - #region DetailsChanged event + #region DetailsChanged Event internal event EventHandler DetailsChanged; private void OnDetailsChanged( object sender, EventArgs e ) { - if( this.DetailsChanged != null ) - { - this.DetailsChanged( sender, e ); - } + var handler = this.DetailsChanged; + if( handler == null ) + return; + + handler.Invoke( sender, e ); } #endregion #region DeletingSelectedItems Event - public static readonly RoutedEvent DeletingSelectedItemsEvent = - EventManager.RegisterRoutedEvent( "DeletingSelectedItems", RoutingStrategy.Bubble, typeof( CancelRoutedEventHandler ), typeof( DataGridControl ) ); + public static readonly RoutedEvent DeletingSelectedItemsEvent = EventManager.RegisterRoutedEvent( + "DeletingSelectedItems", + RoutingStrategy.Bubble, + typeof( CancelRoutedEventHandler ), + typeof( DataGridControl ) ); public event CancelRoutedEventHandler DeletingSelectedItems { @@ -2642,12 +2731,15 @@ namespace Xceed.Wpf.DataGrid this.RaiseEvent( e ); } - #endregion DeletingSelectedItems Event + #endregion #region SelectedItemsDeleted Event - public static readonly RoutedEvent SelectedItemsDeletedEvent = - EventManager.RegisterRoutedEvent( "SelectedItemsDeleted", RoutingStrategy.Bubble, typeof( RoutedEventHandler ), typeof( DataGridControl ) ); + public static readonly RoutedEvent SelectedItemsDeletedEvent = EventManager.RegisterRoutedEvent( + "SelectedItemsDeleted", + RoutingStrategy.Bubble, + typeof( RoutedEventHandler ), + typeof( DataGridControl ) ); public event RoutedEventHandler SelectedItemsDeleted { @@ -2663,16 +2755,18 @@ namespace Xceed.Wpf.DataGrid protected virtual void OnSelectedItemsDeleted() { - RoutedEventArgs e = new RoutedEventArgs( DataGridControl.SelectedItemsDeletedEvent, this ); - this.RaiseEvent( e ); + this.RaiseEvent( new RoutedEventArgs( DataGridControl.SelectedItemsDeletedEvent, this ) ); } - #endregion SelectedItemsDeleted Event + #endregion #region SelectionChanged Event - public static readonly RoutedEvent SelectionChangedEvent = - EventManager.RegisterRoutedEvent( "SelectionChanged", RoutingStrategy.Bubble, typeof( DataGridSelectionChangedEventHandler ), typeof( DataGridControl ) ); + public static readonly RoutedEvent SelectionChangedEvent = EventManager.RegisterRoutedEvent( + "SelectionChanged", + RoutingStrategy.Bubble, + typeof( DataGridSelectionChangedEventHandler ), + typeof( DataGridControl ) ); public event DataGridSelectionChangedEventHandler SelectionChanged { @@ -2696,12 +2790,15 @@ namespace Xceed.Wpf.DataGrid this.OnSelectionChanged( e ); } - #endregion SelectionChanged Event + #endregion #region SelectionChanging Event - public static readonly RoutedEvent SelectionChangingEvent = - EventManager.RegisterRoutedEvent( "SelectionChanging", RoutingStrategy.Bubble, typeof( DataGridSelectionChangingEventHandler ), typeof( DataGridControl ) ); + public static readonly RoutedEvent SelectionChangingEvent = EventManager.RegisterRoutedEvent( + "SelectionChanging", + RoutingStrategy.Bubble, + typeof( DataGridSelectionChangingEventHandler ), + typeof( DataGridControl ) ); public event DataGridSelectionChangingEventHandler SelectionChanging { @@ -2728,12 +2825,15 @@ namespace Xceed.Wpf.DataGrid } } - #endregion SelectionChanging Event + #endregion #region DeletingSelectedItemError Event - public static readonly RoutedEvent DeletingSelectedItemErrorEvent = - EventManager.RegisterRoutedEvent( "DeletingSelectedItemError", RoutingStrategy.Bubble, typeof( DeletingSelectedItemErrorRoutedEventHandler ), typeof( DataGridControl ) ); + public static readonly RoutedEvent DeletingSelectedItemErrorEvent = EventManager.RegisterRoutedEvent( + "DeletingSelectedItemError", + RoutingStrategy.Bubble, + typeof( DeletingSelectedItemErrorRoutedEventHandler ), + typeof( DataGridControl ) ); public event DeletingSelectedItemErrorRoutedEventHandler DeletingSelectedItemError { @@ -2752,7 +2852,7 @@ namespace Xceed.Wpf.DataGrid this.RaiseEvent( e ); } - #endregion DeletingSelectedItemError Event + #endregion #region CurrentChanging Event @@ -2818,131 +2918,259 @@ namespace Xceed.Wpf.DataGrid #endregion - #region Event handlers + #region SortDirectionChanging Event - private static void OnFlowDirectionPropertyChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) + public static readonly RoutedEvent SortDirectionChangingEvent = EventManager.RegisterRoutedEvent( + "SortDirectionChanging", + RoutingStrategy.Bubble, + typeof( ColumnSortDirectionChangingEventHandler ), + typeof( DataGridControl ) ); + + public event ColumnSortDirectionChangingEventHandler SortDirectionChanging { - DataGridControl dataGrid = sender as DataGridControl; - if( dataGrid != null ) + add + { + base.AddHandler( DataGridControl.SortDirectionChangingEvent, value ); + } + remove { - dataGrid.CustomItemContainerGenerator.ResetGeneratorContent(); + base.RemoveHandler( DataGridControl.SortDirectionChangingEvent, value ); } } - private void OnDataGridCollectionView_RootGroupChanged( object sender, EventArgs e ) + protected virtual void OnSortDirectionChanging( ColumnSortDirectionChangingEventArgs e ) { - this.SetValue( DataGridControl.StatContextPropertyKey, ( ( DataGridCollectionView )sender ).RootGroup ); + this.RaiseEvent( e ); } - private void OnDetailConfigurationsChanged( object sender, NotifyCollectionChangedEventArgs e ) + internal void RaiseSortDirectionChanging( ColumnSortDirectionChangingEventArgs e ) { - this.OnNotifyPropertyChanged( new PropertyChangedEventArgs( "HasDetails" ) ); + this.OnSortDirectionChanging( e ); + } - DataGridDetailDescriptionCollection detailDescriptions = null; - DataGridCollectionViewBase dataGridCollectionViewBase = this.ItemsSource as DataGridCollectionViewBase; + #endregion - if( dataGridCollectionViewBase != null ) - detailDescriptions = dataGridCollectionViewBase.DetailDescriptions; + #region GroupCollapsing Event - switch( e.Action ) - { - case NotifyCollectionChangedAction.Replace: - case NotifyCollectionChangedAction.Add: - DetailConfiguration.SynchronizeAddedConfigurations( e.NewItems, detailDescriptions ); - break; - case NotifyCollectionChangedAction.Reset: - case NotifyCollectionChangedAction.Remove: - case NotifyCollectionChangedAction.Move: - default: - break; - } - } + public static readonly RoutedEvent GroupCollapsingEvent = EventManager.RegisterRoutedEvent( + "GroupCollapsing", + RoutingStrategy.Bubble, + typeof( GroupExpansionChangingEventHandler ), + typeof( DataGridControl ) ); - private void OnDataGridDetailDescriptionsChanged( object sender, NotifyCollectionChangedEventArgs e ) + public event GroupExpansionChangingEventHandler GroupCollapsing { - DataGridDetailDescriptionCollection detailDescriptions = sender as DataGridDetailDescriptionCollection; - Debug.Assert( detailDescriptions != null ); - - switch( e.Action ) + add { - case NotifyCollectionChangedAction.Reset: - case NotifyCollectionChangedAction.Replace: - case NotifyCollectionChangedAction.Remove: - case NotifyCollectionChangedAction.Add: - DetailConfiguration.SynchronizeDetailConfigurations( - detailDescriptions, - this.DetailConfigurations, - this.AutoCreateDetailConfigurations, - this.AutoCreateForeignKeyConfigurations, - this.AutoRemoveColumnsAndDetailConfigurations ); - break; - - case NotifyCollectionChangedAction.Move: - //Don't care about the move. - break; - - default: - break; + base.AddHandler( DataGridControl.GroupCollapsingEvent, value ); + } + remove + { + base.RemoveHandler( DataGridControl.GroupCollapsingEvent, value ); } } - private static void OnGroupStyleSelectorChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) + protected virtual void OnGroupCollapsing( GroupExpansionChangingEventArgs e ) { - throw new NotSupportedException( "GroupStyles are not supported by the DataGridControl." ); + this.RaiseEvent( e ); } - private static void GroupStyle_CollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) + internal void RaiseGroupCollapsing( GroupExpansionChangingEventArgs e ) { - if( e.Action == NotifyCollectionChangedAction.Add ) - { - throw new NotSupportedException( "GroupStyles are not supported by the DataGridControl." ); - } + this.OnGroupCollapsing( e ); } #endregion - #region Drag Management + #region GroupCollapsed Event - public bool AllowDrag + public static readonly RoutedEvent GroupCollapsedEvent = EventManager.RegisterRoutedEvent( + "GroupCollapsed", + RoutingStrategy.Bubble, + typeof( GroupExpansionChangedEventHandler ), + typeof( DataGridControl ) ); + + public event GroupExpansionChangedEventHandler GroupCollapsed { - get + add { - return ( bool )GetValue( DataGridControl.AllowDragProperty ); + base.AddHandler( DataGridControl.GroupCollapsedEvent, value ); } - set + remove + { + base.RemoveHandler( DataGridControl.GroupCollapsedEvent, value ); + } + } + + protected virtual void OnGroupCollapsed( GroupExpansionChangedEventArgs e ) + { + this.RaiseEvent( e ); + } + + internal void RaiseGroupCollapsed( GroupExpansionChangedEventArgs e ) + { + this.OnGroupCollapsed( e ); + } + + #endregion + + #region GroupExpanding Event + + public static readonly RoutedEvent GroupExpandingEvent = EventManager.RegisterRoutedEvent( + "GroupExpanding", + RoutingStrategy.Bubble, + typeof( GroupExpansionChangingEventHandler ), + typeof( DataGridControl ) ); + + public event GroupExpansionChangingEventHandler GroupExpanding + { + add + { + base.AddHandler( DataGridControl.GroupExpandingEvent, value ); + } + remove + { + base.RemoveHandler( DataGridControl.GroupExpandingEvent, value ); + } + } + + protected virtual void OnGroupExpanding( GroupExpansionChangingEventArgs e ) + { + this.RaiseEvent( e ); + } + + internal void RaiseGroupExpanding( GroupExpansionChangingEventArgs e ) + { + this.OnGroupExpanding( e ); + } + + #endregion + + #region GroupExpanded Event + + public static readonly RoutedEvent GroupExpandedEvent = EventManager.RegisterRoutedEvent( + "GroupExpanded", + RoutingStrategy.Bubble, + typeof( GroupExpansionChangedEventHandler ), + typeof( DataGridControl ) ); + + public event GroupExpansionChangedEventHandler GroupExpanded + { + add { - SetValue( DataGridControl.AllowDragProperty, value ); + base.AddHandler( DataGridControl.GroupExpandedEvent, value ); } + remove + { + base.RemoveHandler( DataGridControl.GroupExpandedEvent, value ); + } + } + + protected virtual void OnGroupExpanded( GroupExpansionChangedEventArgs e ) + { + this.RaiseEvent( e ); } - public static readonly DependencyProperty AllowDragProperty = - DependencyProperty.Register( "AllowDrag", typeof( bool ), typeof( DataGridControl ), new UIPropertyMetadata( false, new PropertyChangedCallback( DataGridControl.OnAllowDragPropertyChanged ) ) ); + internal void RaiseGroupExpanded( GroupExpansionChangedEventArgs e ) + { + this.OnGroupExpanded( e ); + } + + #endregion + + #region Event Handlers + + private static void OnFlowDirectionPropertyChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) + { + var self = sender as DataGridControl; + if( self == null ) + return; + + self.CustomItemContainerGenerator.ResetGeneratorContent(); + } - private static void OnAllowDragPropertyChanged( DependencyObject obj, DependencyPropertyChangedEventArgs e ) + private void OnDataGridCollectionView_PropertyChanged( DataGridCollectionViewBase sender, PropertyChangedEventArgs e ) { - DataGridControl dataGrid = obj as DataGridControl; + Debug.Assert( sender != null ); + Debug.Assert( e != null ); + + var propertyName = e.PropertyName; - if( ( dataGrid == null ) || ( ( bool )e.NewValue ) ) + if( string.IsNullOrEmpty( propertyName ) || ( propertyName == DataGridCollectionViewBase.RootGroupPropertyName ) ) { + this.SetValue( DataGridControl.StatContextPropertyKey, sender.RootGroup ); + } + } + + private void OnDataGridDetailDescriptionsChanged( DataGridDetailDescriptionCollection sender, NotifyCollectionChangedEventArgs e ) + { + if( sender == null ) return; + + switch( e.Action ) + { + case NotifyCollectionChangedAction.Reset: + case NotifyCollectionChangedAction.Replace: + case NotifyCollectionChangedAction.Remove: + case NotifyCollectionChangedAction.Add: + break; + + case NotifyCollectionChangedAction.Move: + //Don't care about the move. + break; + + default: + break; } + } - dataGrid.ResetDragDataObject(); + private static void OnGroupStyleSelectorChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) + { + throw new NotSupportedException( "GroupStyles are not supported by the DataGridControl." ); } - internal bool UseDragBehavior + private static void GroupStyle_CollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) + { + if( e.Action == NotifyCollectionChangedAction.Add ) + { + throw new NotSupportedException( "GroupStyles are not supported by the DataGridControl." ); + } + } + + #endregion + + #region Drag Management + + public static readonly DependencyProperty AllowDragProperty = DependencyProperty.Register( + "AllowDrag", + typeof( bool ), + typeof( DataGridControl ), + new UIPropertyMetadata( false, new PropertyChangedCallback( DataGridControl.OnAllowDragPropertyChanged ) ) ); + + public bool AllowDrag { get { - return this.AllowDrag; + return ( bool )GetValue( DataGridControl.AllowDragProperty ); + } + set + { + this.SetValue( DataGridControl.AllowDragProperty, value ); } } - internal IDataObject DragDataObject + private static void OnAllowDragPropertyChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) + { + var self = sender as DataGridControl; + if( ( self == null ) || ( ( bool )e.NewValue ) ) + return; + } + + internal bool UseDragBehavior { get { - return m_dragDataObject; + return false; } } @@ -2956,36 +3184,18 @@ namespace Xceed.Wpf.DataGrid internal void DoDrag( MouseEventArgs e ) { - if( !this.AllowDrag ) - return; - - //If we have effect, it means the drag is already processing, no need to do anything further. - if( m_dragDropEffects != null ) - return; - - // Compare the present mouse position to the inital drag position, as to start the drag only if there is a reasonable mouse movement - if( ( m_initialDragPosition != null ) && ( m_initialDragPosition.HasValue ) ) - { - Point currentMousePosition = e.GetPosition( this ); - - if( DragDropHelper.IsMouseMoveDrag( m_initialDragPosition.Value, currentMousePosition ) ) - { - //The first time the drag operation starts, we need to initialize the data that will be dragged. - if( m_dragDataObject == null ) - { - this.PrepareDragDataObject( e ); - } - - m_dragDropEffects = DragDrop.DoDragDrop( this, m_dragDataObject, DragDropEffects.Copy ); - } - } + return; } internal void ResetDragDataObject() { m_dragDataObject = null; m_initialDragPosition = null; - m_dragDropEffects = null; + } + + internal IDisposable InhibitDrag() + { + return m_inhibitDrag.Set(); } private void PrepareDragDataObject( MouseEventArgs e ) @@ -3007,9 +3217,9 @@ namespace Xceed.Wpf.DataGrid private IDataObject m_dragDataObject; // = null; private Nullable m_initialDragPosition; // = null; - private Nullable m_dragDropEffects; // = null; + private readonly AutoResetFlag m_inhibitDrag = AutoResetFlagFactory.Create( false ); - #endregion Drag Management + #endregion #region VIEWBASE METHODS @@ -3036,19 +3246,18 @@ namespace Xceed.Wpf.DataGrid private void View_ThemeChanged( object sender, DependencyPropertyChangedEventArgs e ) { - this.QueueDataGridContextPeerChlidrenRefresh( this.DataGridContext ); // We need to reevaluate the CurrentContext when it is a detail context since the details are cleared and recreated when the theme changes and no update is // made to the current item itself. We dispatch it with a high priority in order to be sure it is executed before a potential BringIntoView of the current item. if( this.CurrentContext != this.DataGridContext ) { - this.Dispatcher.BeginInvoke( new Action( delegate() + this.Dispatcher.BeginInvoke( new Action( delegate () { this.UpdateCurrentContextOnThemeChanged( this.CurrentContext ); } ), DispatcherPriority.Normal ); } - Xceed.Wpf.DataGrid.Views.ViewBase view = this.GetView(); + var view = this.GetView(); this.SaveDataGridContextState( this.DataGridContext, true, int.MaxValue ); @@ -3065,11 +3274,11 @@ namespace Xceed.Wpf.DataGrid // Reset the flag this.ForceGeneratorReset = false; - ControlTemplate oldTemplate = this.Template; + var oldTemplate = this.Template; this.DefaultStyleKey = view.GetDefaultStyleKey( typeof( DataGridControl ) ); - ControlTemplate newTemplate = this.Template; + var newTemplate = this.Template; this.ClearValue( DataGridControl.ParentDataGridControlPropertyKey ); this.SetValue( DataGridControl.ParentDataGridControlPropertyKey, this ); @@ -3077,7 +3286,9 @@ namespace Xceed.Wpf.DataGrid // When a null Theme is set or the new Theme is the already the applied System Theme, we detect if the // template changed after setting the DefaultStyleKey to refresh the FixedHeaders and FixedFooters if( oldTemplate == newTemplate ) + { this.ResetFixedRegions(); + } // Make sure the current item is into view. this.DelayBringIntoViewAndFocusCurrent( DispatcherPriority.Render, AutoScrollCurrentItemSourceTriggers.ThemeChanged ); @@ -3089,21 +3300,7 @@ namespace Xceed.Wpf.DataGrid /// private void InvalidateViewStyle() { - if( this.IsPrinting ) - { - Xceed.Wpf.DataGrid.Views.ViewBase viewBase = this.GetView(); - - // If more than one DataGridPaginator is paginating, the ViewStyle is already invalidated and - // the PrintView is already a logical child. - if( LogicalTreeHelper.GetParent( viewBase ) == null ) - { - this.AddLogicalChild( viewBase ); - } - } - else - { - this.AddLogicalChild( this.GetView() ); - } + this.AddLogicalChild( this.View ); } [Browsable( false )] @@ -3117,32 +3314,22 @@ namespace Xceed.Wpf.DataGrid } } - internal Xceed.Wpf.DataGrid.Views.ViewBase GetView( bool getViewOrDefault = true ) + internal Views.ViewBase GetView() { - UIViewBase view = this.View; - if( view != null ) - return view; - - if( getViewOrDefault ) - { - this.View = this.GetDefaultView() as UIViewBase; - return this.View; - } - - return null; + return this.View; } - private Xceed.Wpf.DataGrid.Views.ViewBase GetDefaultView() + private Views.ViewBase GetDefaultView() { if( m_defaultView == null ) { - m_defaultView = new Xceed.Wpf.DataGrid.Views.TableflowView(); + m_defaultView = new TableflowView(); } return m_defaultView; } - #endregion VIEWBASE METHODS + #endregion #region FOCUS @@ -3260,26 +3447,33 @@ namespace Xceed.Wpf.DataGrid Debug.Assert( ( column == null ) || ( itemContainerDataGridContext.Columns.Contains( column ) ) ); #endif - UIElement toFocus = null; + var toFocus = default( UIElement ); - Row row = Row.FromContainer( itemContainer ); - - IDisposable preventMakeVisibleDisposable = null; + var row = Row.FromContainer( itemContainer ); + var preventMakeVisibleDisposable = default( IDisposable ); try { if( row != null ) { - Cell cell = row.Cells[ column ]; + //ColumnManagerRow and derived classes should not be focused + if( row.IsUnfocusable ) + return false; - // The Cell must be in VisualTree to be able to get the focus, else, .Focus() will always return false - if( cell != null ) + var cell = default( Cell ); + if( column != null ) { - cell.EnsureInVisualTree(); + cell = row.Cells[ column ]; - if( preventMakeVisibleIfCellFocused ) + // The cell must be in VisualTree to be able to get the focus, else, .Focus() will always return false + if( cell != null ) { - preventMakeVisibleDisposable = cell.InhibitMakeVisible(); + cell.EnsureInVisualTree(); + + if( preventMakeVisibleIfCellFocused ) + { + preventMakeVisibleDisposable = cell.InhibitMakeVisible(); + } } } @@ -3303,9 +3497,10 @@ namespace Xceed.Wpf.DataGrid toFocus = cell; } - bool currentFocusIsInsideCell = ( cell != Keyboard.FocusedElement ) && ( TreeHelper.IsDescendantOf( Keyboard.FocusedElement as DependencyObject, cell ) ); + var currentFocusIsInsideCell = ( cell != Keyboard.FocusedElement ) && ( TreeHelper.IsDescendantOf( Keyboard.FocusedElement as DependencyObject, cell ) ); - //If the focus is already within the Cell to focus, then don't touch a thing. It means the item to focus should be the Keyboard focused element - Already focused + // If the focus is already within the Cell to focus, there is noting to do. The item to focus should be the Keyboard focused element - hence, already focused. + // Verify cell.IsBeingEdited to prevent the focus to stay on the editor when in fact the editing process is being canceled (pressing ESC). if( ( currentFocusIsInsideCell ) && ( preserveEditorFocus ) && ( cell.IsBeingEdited ) ) return true; } @@ -3327,7 +3522,7 @@ namespace Xceed.Wpf.DataGrid { toFocus = cell; - bool currentFocusIsInsideCell = ( cell != Keyboard.FocusedElement ) && ( TreeHelper.IsDescendantOf( Keyboard.FocusedElement as DependencyObject, cell ) ); + var currentFocusIsInsideCell = ( cell != Keyboard.FocusedElement ) && ( TreeHelper.IsDescendantOf( Keyboard.FocusedElement as DependencyObject, cell ) ); //If the focus is already within the Cell to focus, then don't touch a thing. It means the item to focus should be the Keyboard focused element - Already focused if( ( currentFocusIsInsideCell ) && ( preserveEditorFocus ) ) @@ -3338,16 +3533,16 @@ namespace Xceed.Wpf.DataGrid { toFocus = itemContainer; - //if the container for the item is not a Row, and the focus is already within that item then don't touch the focus. - bool partOfContainer = TreeHelper.IsDescendantOf( Keyboard.FocusedElement as DependencyObject, toFocus ); - - if( partOfContainer ) - { + if( TreeHelper.IsDescendantOf( Keyboard.FocusedElement as DependencyObject, toFocus ) ) return true; - } } - return DataGridControl.SetFocusUIElementHelper( toFocus ); + // If setting the focus on a row fails, we must try to focus the item container in case the target row is not the topmost container, + // i.e. a StatRow that is contained in a a GroupHeaderControl. + if( ( toFocus != itemContainer ) && DataGridControl.SetFocusUIElementHelper( toFocus ) ) + return true; + + return DataGridControl.SetFocusUIElementHelper( itemContainer ); } finally { @@ -3384,10 +3579,21 @@ namespace Xceed.Wpf.DataGrid } } - #endregion FOCUS + #endregion #region BRING INTO VIEW + internal bool IsBringIntoViewDelayed + { + get + { + var itemsHost = this.ItemsHost as DataGridItemsHost; + + return ( itemsHost != null ) + && ( itemsHost.DelayBringIntoView ); + } + } + internal IDisposable SetQueueBringIntoViewRestrictions( AutoScrollCurrentItemSourceTriggers trigger ) { return m_inhibitAutoScroll.SetRestriction( trigger ); @@ -3462,17 +3668,22 @@ namespace Xceed.Wpf.DataGrid if( itemsHostDataGridContext == null ) return false; - //if a container exists, call bring into view on it! - var container = dataGridContext.GetContainerFromItem( item ) as FrameworkElement; - if( container != null ) + // We don't want to call BringIntoView directly on the container if a layout pass + // is scheduled. + if( !this.IsBringIntoViewDelayed ) { - container.BringIntoView(); + // If a container exists, call bring into view on it! + var container = dataGridContext.GetContainerFromItem( item ) as FrameworkElement; + if( container != null ) + { + container.BringIntoView(); - //flag the function as being successful - return true; + //flag the function as being successful + return true; + } } - // The container does not exist, it is not yet realized. + // The container does not exist, it is not yet realized or the action is delayed. // If we are not virtualizing any items, return. // The call to SetFocusHelper when the BringIntoView completes will call a FrameworkElement BringIntoView @@ -3565,7 +3776,7 @@ namespace Xceed.Wpf.DataGrid return ( ( source & comparand ) == comparand ); } - #endregion BRING INTO VIEW + #endregion #region COMMANDS @@ -3573,98 +3784,66 @@ namespace Xceed.Wpf.DataGrid { e.CanExecute = false; - CollectionViewGroup group = e.Parameter as CollectionViewGroup; - if( ( e.Parameter != null ) && ( group != null ) ) + var group = e.Parameter as CollectionViewGroup; + if( group == null ) + return; + + if( this.DataGridContext.IsGroupExpanded( group, false ) == false ) { - try - { - if( this.DataGridContext.IsGroupExpandedCore( group, true ) == false ) - { - e.CanExecute = true; - } - } - catch( InvalidOperationException ) - { //suppress - } + e.CanExecute = true; } } protected virtual void OnExpandGroupExecuted( object sender, ExecutedRoutedEventArgs e ) { - CollectionViewGroup cvg = e.Parameter as CollectionViewGroup; - if( cvg != null ) - { - try - { - this.DataGridContext.ExpandGroup( cvg ); - } - catch( InvalidOperationException ) - { - //suppress - } - } + var group = e.Parameter as CollectionViewGroup; + if( group == null ) + return; + + this.DataGridContext.ExpandGroup( group ); } private void OnCollapseGroupCanExecute( object sender, CanExecuteRoutedEventArgs e ) { e.CanExecute = false; - CollectionViewGroup group = e.Parameter as CollectionViewGroup; - if( ( e.Parameter != null ) && ( group != null ) ) + var group = e.Parameter as CollectionViewGroup; + if( group == null ) + return; + + if( this.DataGridContext.IsGroupExpanded( group, false ) == true ) { - try - { - if( this.DataGridContext.IsGroupExpandedCore( group, true ) == true ) - { - e.CanExecute = true; - } - } - catch( InvalidOperationException ) - { //suppress - } + e.CanExecute = true; } } protected virtual void OnCollapseGroupExecuted( object sender, ExecutedRoutedEventArgs e ) { - CollectionViewGroup cvg = e.Parameter as CollectionViewGroup; - if( cvg != null ) - { - try - { - this.DataGridContext.CollapseGroup( cvg ); - } - catch( InvalidOperationException ) - { - //suppress - } - } + var group = e.Parameter as CollectionViewGroup; + if( group == null ) + return; + + this.DataGridContext.CollapseGroup( group ); } private void OnToggleGroupCanExecute( object sender, CanExecuteRoutedEventArgs e ) { e.CanExecute = false; - if( ( e.Parameter != null ) && ( e.Parameter is CollectionViewGroup ) ) - { - e.CanExecute = true; - } + var group = e.Parameter as CollectionViewGroup; + if( group == null ) + return; + + e.CanExecute = this.DataGridContext.IsGroupExpanded( group, false ).HasValue; } protected virtual void OnToggleGroupExecuted( object sender, ExecutedRoutedEventArgs e ) { - CollectionViewGroup cvg = e.Parameter as CollectionViewGroup; - if( cvg != null ) - { - try - { - this.DataGridContext.ToggleGroupExpansion( cvg ); - } - catch( InvalidOperationException ) - { - //suppress - } - } + var group = e.Parameter as CollectionViewGroup; + if( group == null ) + return; + + this.DataGridContext.ToggleGroupExpansion( group ); } private void OnSelectAllCanExecute( object sender, CanExecuteRoutedEventArgs e ) @@ -3698,14 +3877,7 @@ namespace Xceed.Wpf.DataGrid } finally { - try - { - this.SelectionChangerManager.End( false, true, false ); - } - catch( DataGridException ) - { - // This is to swallow when selection is aborted - } + this.SelectionChangerManager.End( true, false ); } } @@ -3748,21 +3920,15 @@ namespace Xceed.Wpf.DataGrid { foreach( DataGridContext dataGridContext in this.SelectedContexts ) { - if( ( !dataGridContext.IsDeleteCommandEnabled ) || - ( dataGridContext.SelectedItems.Count == 0 ) ) - { + if( ( !dataGridContext.IsDeleteCommandEnabled ) || ( dataGridContext.SelectedItems.Count == 0 ) ) continue; - } - DataGridCollectionViewBase dataGridCollectionViewBase = - dataGridContext.ItemsSourceCollection as DataGridCollectionViewBase; + DataGridCollectionViewBase dataGridCollectionViewBase = dataGridContext.ItemsSourceCollection as DataGridCollectionViewBase; - IList list = ( dataGridCollectionViewBase == null ) - ? ItemsSourceHelper.TryGetIList( dataGridContext.ItemsSourceCollection ) - : null; // If we already have a DataGridCollectionView, no need to look for an IList source. + // If we already have a DataGridCollectionView, no need to look for an IList source. + IList list = ( dataGridCollectionViewBase == null ) ? ItemsSourceHelper.TryGetIList( dataGridContext.ItemsSourceCollection ) : null; - if( ( dataGridCollectionViewBase != null ) - || ( ( list != null ) && DataGridControl.IsRemoveAllowedForDeleteCommand( list ) ) ) + if( ( dataGridCollectionViewBase != null ) || ( ( list != null ) && DataGridControl.IsRemoveAllowedForDeleteCommand( list ) ) ) { // Ensure that at least on item can be deleted. foreach( object item in dataGridContext.SelectedItems ) @@ -3821,15 +3987,12 @@ namespace Xceed.Wpf.DataGrid if( ( !dataGridContext.IsDeleteCommandEnabled ) || ( selectedItems.Length == 0 ) ) continue; - DataGridCollectionViewBase dataGridCollectionViewBase = - dataGridContext.ItemsSourceCollection as DataGridCollectionViewBase; + DataGridCollectionViewBase dataGridCollectionViewBase = dataGridContext.ItemsSourceCollection as DataGridCollectionViewBase; - IList list = ( dataGridCollectionViewBase == null ) - ? ItemsSourceHelper.TryGetIList( dataGridContext.ItemsSourceCollection ) - : null; // If we already have a DataGridCollectionView, no need to look for an IList source. + // If we already have a DataGridCollectionView, no need to look for an IList source. + IList list = ( dataGridCollectionViewBase == null ) ? ItemsSourceHelper.TryGetIList( dataGridContext.ItemsSourceCollection ) : null; - if( ( dataGridCollectionViewBase != null ) - || ( ( list != null ) && DataGridControl.IsRemoveAllowedForDeleteCommand( list ) ) ) + if( ( dataGridCollectionViewBase != null ) || ( ( list != null ) && DataGridControl.IsRemoveAllowedForDeleteCommand( list ) ) ) { foreach( object item in selectedItems ) { @@ -3846,14 +4009,18 @@ namespace Xceed.Wpf.DataGrid itemIndex = dataGridCollectionViewBase.IndexOf( item ); if( itemIndex != -1 ) + { dataGridCollectionViewBase.RemoveAt( itemIndex ); + } } else if( list != null ) { itemIndex = list.IndexOf( item ); if( itemIndex != -1 ) + { list.RemoveAt( itemIndex ); + } } retry = false; @@ -3861,7 +4028,9 @@ namespace Xceed.Wpf.DataGrid } catch( Exception ex ) { - DeletingSelectedItemErrorRoutedEventArgs deletingItemErrorArgs = new DeletingSelectedItemErrorRoutedEventArgs( item, ex, DataGridControl.DeletingSelectedItemErrorEvent, this ); + DeletingSelectedItemErrorRoutedEventArgs deletingItemErrorArgs = + new DeletingSelectedItemErrorRoutedEventArgs( item, ex, DataGridControl.DeletingSelectedItemErrorEvent, this ); + this.OnDeletingSelectedItemError( deletingItemErrorArgs ); switch( deletingItemErrorArgs.Action ) @@ -3881,7 +4050,9 @@ namespace Xceed.Wpf.DataGrid } if( raiseItemDeleted ) + { this.OnSelectedItemsDeleted(); + } } private void OnRefreshCanExecute( object sender, CanExecuteRoutedEventArgs e ) @@ -3904,54 +4075,25 @@ namespace Xceed.Wpf.DataGrid } } - protected virtual void OnClearFilterExecuted( object sender, ExecutedRoutedEventArgs e ) - { - DataGridCollectionViewBase dgcv = this.ItemsSource as DataGridCollectionViewBase; - - if( dgcv != null ) - { - using( dgcv.DeferRefresh() ) - { - foreach( DataGridItemPropertyBase itemProperty in dgcv.ItemProperties ) - { - if( itemProperty.FilterCriterion != null ) - { - itemProperty.FilterCriterion = null; - } - } - - foreach( DataGridDetailDescription detailDescription in dgcv.DetailDescriptions ) - { - foreach( DataGridItemPropertyBase itemProperty in detailDescription.ItemProperties ) - { - if( itemProperty.FilterCriterion != null ) - { - itemProperty.FilterCriterion = null; - } - } - } - } - } - } - #endregion #region SOURCE HANDLING private void ProcessDelayedItemsSourceChanged() { + var dataGridContext = this.DataGridContext; + if( this.ShouldSynchronizeCurrentItem ) { - DataGridContext localContext = this.DataGridContext; - object currentItem = this.Items.CurrentItem; - int currentItemIndex = this.Items.CurrentPosition; + var currentItem = this.Items.CurrentItem; + var currentItemIndex = this.Items.CurrentPosition; if( ( this.Items.IsCurrentAfterLast ) || ( this.Items.IsCurrentBeforeFirst ) ) { currentItemIndex = -1; } - localContext.SetCurrent( currentItem, null, currentItemIndex, null, false, false, this.SynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.ItemsSourceChanged ); + dataGridContext.SetCurrent( currentItem, null, currentItemIndex, null, false, false, this.SynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.ItemsSourceChanged ); if( !this.SynchronizeSelectionWithCurrent ) { @@ -3959,12 +4101,9 @@ namespace Xceed.Wpf.DataGrid try { - if( ( this.SelectionUnit == SelectionUnit.Row ) - && ( !this.Items.IsCurrentAfterLast ) - && ( !this.Items.IsCurrentBeforeFirst ) - && ( currentItemIndex != -1 ) ) + if( ( this.SelectionUnit == SelectionUnit.Row ) && ( !this.Items.IsCurrentAfterLast ) && ( !this.Items.IsCurrentBeforeFirst ) && ( currentItemIndex != -1 ) ) { - m_selectionChangerManager.SelectJustThisItem( localContext, currentItemIndex, currentItem ); + m_selectionChangerManager.SelectJustThisItem( dataGridContext, currentItemIndex, currentItem ); } else { @@ -3973,61 +4112,57 @@ namespace Xceed.Wpf.DataGrid } finally { - m_selectionChangerManager.End( true, false, false ); + m_selectionChangerManager.End( false, false ); } } } - this.DataGridContext.ItemsSourceFieldDescriptors = null; - ItemsSourceHelper.CleanUpColumns( this.Columns, this.AutoRemoveColumnsAndDetailConfigurations ); - this.GenerateColumnsFromItemsSourceFields(); + var columnManager = dataGridContext.ColumnManager; - DataGridCollectionView dataGridCollectionView = this.ItemsSource as DataGridCollectionView; - - if( dataGridCollectionView != null ) + using( columnManager.DeferUpdate( new ColumnHierarchyManager.UpdateOptions( TableView.GetFixedColumnCount( dataGridContext ), true ) ) ) { - RootGroupChangedEventManager.AddListener( dataGridCollectionView, this ); - this.SetValue( DataGridControl.StatContextPropertyKey, dataGridCollectionView.RootGroup ); + ItemsSourceHelper.ResetPropertyDescriptions( m_itemsSourcePropertyDescriptions, m_itemPropertyMap, this, this.ItemsSource ); + ItemsSourceHelper.CleanUpColumns( this.Columns, false ); - CollectionChangedEventManager.AddListener( dataGridCollectionView.DetailDescriptions, this ); - - DetailConfiguration.SynchronizeDetailConfigurations( - dataGridCollectionView.DetailDescriptions, - this.DetailConfigurations, - this.AutoCreateDetailConfigurations, - this.AutoCreateForeignKeyConfigurations, - this.AutoRemoveColumnsAndDetailConfigurations ); + if( this.AutoCreateColumns ) + { + ItemsSourceHelper.CreateColumnsFromPropertyDescriptions( this.DataGridContext.ColumnManager, + this.DefaultCellEditors, + m_itemsSourcePropertyDescriptions, + this.AutoCreateForeignKeyConfigurations ); + } - ProxyCollectionRefreshEventManager.AddListener( dataGridCollectionView, this ); - ProxyGroupDescriptionsChangedEventManager.AddListener( dataGridCollectionView, this ); - ProxySortDescriptionsChangedEventManager.AddListener( dataGridCollectionView, this ); - ProxyAutoFilterValuesChangedEventManager.AddListener( dataGridCollectionView, this ); - ProxyApplyingFilterCriteriasEventManager.AddListener( dataGridCollectionView, this ); - } - else - { - DetailConfiguration.CleanupDetailConfigurations( this.DetailConfigurations, this.AutoRemoveColumnsAndDetailConfigurations ); - this.ClearValue( DataGridControl.StatContextPropertyKey ); - } + var dataGridCollectionView = this.ItemsSource as DataGridCollectionView; + if( dataGridCollectionView != null ) + { + PropertyChangedEventManager.AddListener( dataGridCollectionView, this, string.Empty ); + this.SetValue( DataGridControl.StatContextPropertyKey, dataGridCollectionView.RootGroup ); - DataGridVirtualizingCollectionViewBase virtualizingCollectionView = this.ItemsSource as DataGridVirtualizingCollectionViewBase; + ProxyCollectionRefreshEventManager.AddListener( dataGridCollectionView, this ); + ProxyGroupDescriptionsChangedEventManager.AddListener( dataGridCollectionView, this ); + ProxySortDescriptionsChangedEventManager.AddListener( dataGridCollectionView, this ); + } + else + { + this.ClearValue( DataGridControl.StatContextPropertyKey ); + } - // Keep if the source is bound to DataGridVirtualizingCollectionView - // to avoid preserving ContainerSizeState to avoid memory leaks - this.IsBoundToDataGridVirtualizingCollectionViewBase = ( virtualizingCollectionView != null ); + var virtualizingCollectionView = this.ItemsSource as DataGridVirtualizingCollectionViewBase; - if( this.IsBoundToDataGridVirtualizingCollectionViewBase ) - { - ConnectionStateChangedEventManager.AddListener( virtualizingCollectionView, this ); - ConnectionErrorChangedEventManager.AddListener( virtualizingCollectionView, this ); - } + // Keep if the source is bound to DataGridVirtualizingCollectionView to avoid preserving ContainerSizeState to avoid memory leaks + this.IsBoundToDataGridVirtualizingCollectionViewBase = ( virtualizingCollectionView != null ); - this.DataGridContext.NotifyItemsSourceChanged(); + if( this.IsBoundToDataGridVirtualizingCollectionViewBase ) + { + ConnectionStateChangedEventManager.AddListener( virtualizingCollectionView, this ); + ConnectionErrorChangedEventManager.AddListener( virtualizingCollectionView, this ); + } - if( this.ItemsSourceChangeCompleted != null ) - { - this.ItemsSourceChangeCompleted( this, EventArgs.Empty ); + columnManager.Initialize( this ); } + + dataGridContext.NotifyItemsSourceChanged(); + this.OnItemsSourceChangeCompleted(); } [Obsolete( "The AddingNewDataItem event is obsolete and has been replaced by the DataGridCollectionView.CreatingNewItem and InitializingNewItem events.", false )] @@ -4048,6 +4183,15 @@ namespace Xceed.Wpf.DataGrid public event EventHandler ItemsSourceChangeCompleted; + private void OnItemsSourceChangeCompleted() + { + var handler = this.ItemsSourceChangeCompleted; + if( handler == null ) + return; + + handler.Invoke( this, EventArgs.Empty ); + } + protected override void OnItemsSourceChanged( IEnumerable oldValue, IEnumerable newValue ) { base.OnItemsSourceChanged( oldValue, newValue ); @@ -4082,14 +4226,14 @@ namespace Xceed.Wpf.DataGrid if( !object.Equals( this.ItemsSourceName, oldItemsSourceName ) ) { - this.OnNotifyPropertyChanged( new PropertyChangedEventArgs( "ItemsSourceName" ) ); + this.OnPropertyChanged( "ItemsSourceName" ); } DataGridContext localContext = this.DataGridContext; this.UpdateCurrentRowInEditionCellStates( null, null ); localContext.ClearSizeStates(); - if( m_beginInitCount > 0 ) + if( m_initCount != 0 ) { this.ItemsSourceChangedDelayed = true; } @@ -4102,14 +4246,11 @@ namespace Xceed.Wpf.DataGrid if( dataGridCollectionView != null ) { - RootGroupChangedEventManager.RemoveListener( dataGridCollectionView, this ); - CollectionChangedEventManager.RemoveListener( dataGridCollectionView.DetailDescriptions, this ); + PropertyChangedEventManager.RemoveListener( dataGridCollectionView, this, string.Empty ); ProxyCollectionRefreshEventManager.RemoveListener( dataGridCollectionView, this ); ProxyGroupDescriptionsChangedEventManager.RemoveListener( dataGridCollectionView, this ); ProxySortDescriptionsChangedEventManager.RemoveListener( dataGridCollectionView, this ); - ProxyAutoFilterValuesChangedEventManager.RemoveListener( dataGridCollectionView, this ); - ProxyApplyingFilterCriteriasEventManager.RemoveListener( dataGridCollectionView, this ); m_dataGridContextsStateDictionary = null; } @@ -4137,7 +4278,7 @@ namespace Xceed.Wpf.DataGrid if( currentItem != null ) { // Use Row.FromContainer to ensure Rows in Header/Footers are returned correctly - Row row = Row.FromContainer( currentContext.GetContainerFromItem( currentItem ) ); + var row = Row.FromContainer( currentContext.GetContainerFromItem( currentItem ) ); if( ( row != null ) && ( row.IsBeingEdited ) ) { row.CancelEdit(); @@ -4165,19 +4306,7 @@ namespace Xceed.Wpf.DataGrid return ( ( DataGridControl )sender ).OnCoerceItemsSource( value ); } - private void GenerateColumnsFromItemsSourceFields() - { - if( this.AutoCreateColumns ) - { - ItemsSourceHelper.GenerateColumnsFromItemsSourceFields( - this.DataGridContext.Columns, - this.DefaultCellEditors, - this.DataGridContext.ItemsSourceFieldDescriptors, - this.AutoCreateForeignKeyConfigurations ); - } - } - - #endregion SOURCE HANDLING + #endregion #region SAVE/RESTORE STATE @@ -4277,30 +4406,24 @@ namespace Xceed.Wpf.DataGrid } } - private void OnDataGridCollectionView_ProxyCollectionRefresh( object sender, EventArgs e ) + private void OnDataGridCollectionView_ProxyCollectionRefresh( DataGridCollectionView sender, EventArgs e ) { - DataGridCollectionView dataGridCollectionView = ( DataGridCollectionView )sender; - - ObservableCollection groupDescriptions = dataGridCollectionView.GroupDescriptions; + if( ( sender == null ) || ( sender.GroupDescriptions.Count <= 0 ) ) + return; - if( dataGridCollectionView.GroupDescriptions.Count > 0 ) + var targetDataGridContext = DataGridContext.SafeGetDataGridContextForDataGridCollectionView( this.DataGridContext, sender ); + if( targetDataGridContext != null ) { - DataGridContext targetDataGridContext = DataGridContext.SafeGetDataGridContextForDataGridCollectionView( this.DataGridContext, dataGridCollectionView ); - - if( targetDataGridContext != null ) - { - this.SaveDataGridContextState( targetDataGridContext, false, int.MaxValue ); - } + this.SaveDataGridContextState( targetDataGridContext, false, int.MaxValue ); } } - private void OnDataGridCollectionView_ProxyGroupDescriptionsChanged( object sender, NotifyCollectionChangedEventArgs e ) + private void OnDataGridCollectionView_ProxyGroupDescriptionsChanged( DataGridCollectionView sender, NotifyCollectionChangedEventArgs e ) { - DataGridCollectionView dataGridCollectionView = ( DataGridCollectionView )sender; - - ObservableCollection groupDescriptions = dataGridCollectionView.GroupDescriptions; + if( sender == null ) + return; - int maxGroupLevelToSave = -1; + var maxGroupLevelToSave = -1; switch( e.Action ) { @@ -4316,7 +4439,6 @@ namespace Xceed.Wpf.DataGrid // Only save/restore the state if there's other groups located before the moved group old/new index. // Else, do not save, since we already know that we won't be able to find any match when restoring. maxGroupLevelToSave = Math.Min( e.OldStartingIndex, e.NewStartingIndex ) - 1; - break; } @@ -4342,8 +4464,7 @@ namespace Xceed.Wpf.DataGrid if( maxGroupLevelToSave > -1 ) { - DataGridContext targetDataGridContext = DataGridContext.SafeGetDataGridContextForDataGridCollectionView( this.DataGridContext, dataGridCollectionView ); - + var targetDataGridContext = DataGridContext.SafeGetDataGridContextForDataGridCollectionView( this.DataGridContext, sender ); if( targetDataGridContext != null ) { this.SaveDataGridContextState( targetDataGridContext, false, maxGroupLevelToSave ); @@ -4351,90 +4472,63 @@ namespace Xceed.Wpf.DataGrid } } - private void OnDataGridCollectionView_ProxySortDescriptionsChanged( object sender, NotifyCollectionChangedEventArgs e ) + private void OnDataGridCollectionView_ProxySortDescriptionsChanged( DataGridCollectionView sender, NotifyCollectionChangedEventArgs e ) { - DataGridCollectionView dataGridCollectionView = ( DataGridCollectionView )sender; - - ObservableCollection groupDescriptions = dataGridCollectionView.GroupDescriptions; + if( ( sender == null ) || ( sender.GroupDescriptions.Count <= 0 ) ) + return; - if( dataGridCollectionView.GroupDescriptions.Count > 0 ) + var targetDataGridContext = DataGridContext.SafeGetDataGridContextForDataGridCollectionView( this.DataGridContext, sender ); + if( targetDataGridContext != null ) { - DataGridContext targetDataGridContext = DataGridContext.SafeGetDataGridContextForDataGridCollectionView( this.DataGridContext, dataGridCollectionView ); - - if( targetDataGridContext != null ) - { - this.SaveDataGridContextState( targetDataGridContext, false, int.MaxValue ); - } + this.SaveDataGridContextState( targetDataGridContext, false, int.MaxValue ); } } - private void OnDataGridCollectionView_ProxyAutoFilterValuesChanged( object sender, NotifyCollectionChangedEventArgs e ) + private void OnDataGridCollectionView_ProxyAutoFilterValuesChanged( DataGridCollectionView sender, NotifyCollectionChangedEventArgs e ) { - DataGridCollectionView dataGridCollectionView = ( DataGridCollectionView )sender; - - ObservableCollection groupDescriptions = dataGridCollectionView.GroupDescriptions; + if( ( sender == null ) || ( sender.GroupDescriptions.Count <= 0 ) ) + return; - if( dataGridCollectionView.GroupDescriptions.Count > 0 ) + var targetDataGridContext = DataGridContext.SafeGetDataGridContextForDataGridCollectionView( this.DataGridContext, sender ); + if( targetDataGridContext != null ) { - DataGridContext targetDataGridContext = DataGridContext.SafeGetDataGridContextForDataGridCollectionView( - this.DataGridContext, dataGridCollectionView ); - - if( targetDataGridContext != null ) - this.SaveDataGridContextState( targetDataGridContext, false, int.MaxValue ); + this.SaveDataGridContextState( targetDataGridContext, false, int.MaxValue ); } } - private void OnDataGridCollectionView_ProxyApplyingFilterCriterias( object sender, EventArgs e ) + private void OnDataGridCollectionView_ProxyApplyingFilterCriterias( DataGridCollectionView sender, EventArgs e ) { - DataGridCollectionView dataGridCollectionView = ( DataGridCollectionView )sender; - - ObservableCollection groupDescriptions = dataGridCollectionView.GroupDescriptions; + if( ( sender == null ) || ( sender.GroupDescriptions.Count <= 0 ) ) + return; - if( dataGridCollectionView.GroupDescriptions.Count > 0 ) + var targetDataGridContext = DataGridContext.SafeGetDataGridContextForDataGridCollectionView( this.DataGridContext, sender ); + if( targetDataGridContext != null ) { - DataGridContext targetDataGridContext = DataGridContext.SafeGetDataGridContextForDataGridCollectionView( - this.DataGridContext, dataGridCollectionView ); - - if( targetDataGridContext != null ) - this.SaveDataGridContextState( targetDataGridContext, false, int.MaxValue ); + this.SaveDataGridContextState( targetDataGridContext, false, int.MaxValue ); } } - #endregion SAVE/RESTORE STATE + #endregion #region VIRTUALIZING COLLECTION VIEW SUPPORT - private void OnDataGridVirtualizingCollectionViewBase_ConnectionStateChanged( object sender, EventArgs e ) + private void OnDataGridVirtualizingCollectionViewBase_ConnectionStateChanged( DataGridVirtualizingCollectionViewBase sender, EventArgs e ) { - DataGridVirtualizingCollectionViewBase dataGridVirtualizingCollectionViewBase = sender as DataGridVirtualizingCollectionViewBase; + if( sender == null ) + return; - this.SetConnectionState( dataGridVirtualizingCollectionViewBase.ConnectionState ); + this.SetConnectionState( sender.ConnectionState ); } - private void OnDataGridVirtualizingCollectionViewBase_ConnectionErrorChanged( object sender, EventArgs e ) + private void OnDataGridVirtualizingCollectionViewBase_ConnectionErrorChanged( DataGridVirtualizingCollectionViewBase sender, EventArgs e ) { - DataGridVirtualizingCollectionViewBase dataGridVirtualizingCollectionViewBase = sender as DataGridVirtualizingCollectionViewBase; - - this.SetConnectionError( dataGridVirtualizingCollectionViewBase.ConnectionError ); - } - - #endregion VIRTUALIZING COLLECTION VIEW SUPPORT - - #region PRINTING/EXPORTING + if( sender == null ) + return; - internal bool IsPrinting - { - get - { - return m_flags[ ( int )DataGridControlFlags.UsePrintView ]; - } - private set - { - m_flags[ ( int )DataGridControlFlags.UsePrintView ] = value; - } + this.SetConnectionError( sender.ConnectionError ); } - #endregion PRINTING/EXPORTING + #endregion #region EDITING @@ -4450,26 +4544,26 @@ namespace Xceed.Wpf.DataGrid internal static void BeginEditHelper( DataGridContext dataGridContext, object item ) { - DataGridControl dataGridControl = dataGridContext.DataGridControl; - - if( dataGridControl.IsBeingEdited ) + if( item == null ) return; - if( item == null ) + var dataGridControl = dataGridContext.DataGridControl; + if( dataGridControl.IsBeingEdited ) return; if( !dataGridContext.IsContainingItem( item ) ) throw new InvalidOperationException( "An attempt was made to call the BeginEdit method of an item that is not part of the specified context." ); - DependencyObject container = dataGridContext.GetContainerFromItem( item ); + var container = dataGridContext.GetContainerFromItem( item ); //if the item is realized, then I could call the BeginEdit() directly on the container. if( container != null ) { - Row row = Row.FromContainer( container ); - + var row = Row.FromContainer( container ); if( row != null ) + { row.BeginEdit(); + } //not a row, then not editable. } @@ -4488,27 +4582,27 @@ namespace Xceed.Wpf.DataGrid internal static void EndEditHelper( DataGridContext dataGridContext ) { - DataGridControl dataGridControl = dataGridContext.DataGridControl; - + var dataGridControl = dataGridContext.DataGridControl; if( !dataGridControl.IsBeingEdited ) return; if( !dataGridContext.IsContainingItem( dataGridContext.DataGridControl.CurrentItemInEdition ) ) throw new InvalidOperationException( "An attempt was made to call the EndEdit method of an item that is not part of the specified context." ); - DependencyObject container = dataGridContext.GetContainerFromItem( dataGridControl.m_currentItemInEdition ); + var container = dataGridContext.GetContainerFromItem( dataGridControl.m_currentItemInEdition ); //if the item is realized, then I could call the EndEdit() directly on the container. if( container != null ) { - Row row = Row.FromContainer( container ); - + var row = Row.FromContainer( container ); if( row != null ) + { row.EndEdit(); + } //not a row, then not editable. } - //if the container is not realized, then I need to set things up so that when the container is realized, it's gonna resume edition. + //if the container is not realized, then set things up so that when the container is realized, editing will resume. else { DataGridControl.ProcessUnrealizedEndEdit( dataGridContext ); @@ -4522,23 +4616,23 @@ namespace Xceed.Wpf.DataGrid internal static void CancelEditHelper( DataGridContext dataGridContext ) { - DataGridControl dataGridControl = dataGridContext.DataGridControl; - + var dataGridControl = dataGridContext.DataGridControl; if( !dataGridControl.IsBeingEdited ) return; if( !dataGridContext.IsCurrent ) throw new InvalidOperationException( "An attempt was made to call the CancelEdit method on a DataGridContext that is not current." ); - DependencyObject container = dataGridContext.GetContainerFromItem( dataGridControl.m_currentItemInEdition ); + var container = dataGridContext.GetContainerFromItem( dataGridControl.m_currentItemInEdition ); //if the item is realized, then I could call the CancelEdit() directly on the container. if( container != null ) { - Row row = Row.FromContainer( container ); - + var row = Row.FromContainer( container ); if( row != null ) + { row.CancelEdit(); + } //not a row, then not editable. } @@ -4599,7 +4693,7 @@ namespace Xceed.Wpf.DataGrid { if( newCurrentItemInEdition != m_currentItemInEdition ) { - Row currentRowInEdition = null; + var currentRowInEdition = default( Row ); if( m_currentItemInEdition != null ) { @@ -4621,8 +4715,7 @@ namespace Xceed.Wpf.DataGrid // We must clear the edition state of the old Row in edition foreach( Cell cell in currentRowInEdition.CreatedCells ) { - ColumnBase parentColumn = cell.ParentColumn; - + var parentColumn = cell.ParentColumn; if( parentColumn == null ) continue; @@ -4646,12 +4739,11 @@ namespace Xceed.Wpf.DataGrid { foreach( Cell cell in newCurrentItemContainer.CreatedCells ) { - ColumnBase parentColumn = cell.ParentColumn; - + var parentColumn = cell.ParentColumn; if( parentColumn == null ) continue; - CellState cellState = new CellState(); + var cellState = new CellState(); cellState.SetContentBeforeRowEdition( cell.Content ); parentColumn.CurrentRowInEditionCellState = cellState; @@ -4659,10 +4751,18 @@ namespace Xceed.Wpf.DataGrid } } - #endregion EDITING + #endregion #region SELECTION/CURRENT + internal bool UseDragToSelectBehavior + { + get + { + return false; + } + } + internal bool IsSetCurrentInProgress { get @@ -4683,7 +4783,8 @@ namespace Xceed.Wpf.DataGrid m_queueClearCurrentColumn = null; } - m_queueClearCurrentColumn = this.Dispatcher.BeginInvoke( System.Windows.Threading.DispatcherPriority.DataBind, new ParametrizedGenericHandler( ClearCurrentColumnHandler ), currentItem ); + m_queueClearCurrentColumn = this.Dispatcher.BeginInvoke( System.Windows.Threading.DispatcherPriority.DataBind, + new ParametrizedGenericHandler( ClearCurrentColumnHandler ), currentItem ); } internal void AddToSelectedContexts( DataGridContext context ) @@ -4708,12 +4809,12 @@ namespace Xceed.Wpf.DataGrid { try { - currentDataGridContext.SetCurrent( oldCurrentItem, null, null, null, false, false, this.SynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.Editing ); + currentDataGridContext.SetCurrent( oldCurrentItem, null, null, null, false, false, + this.SynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.Editing ); } catch( DataGridException ) { - // We swallow the exception if it occurs because of a validation error or Cell was read-only or - // any other GridException. + // We swallow the exception if it occurs because of a validation error or Cell was read-only or any other GridException. } } } @@ -4727,20 +4828,14 @@ namespace Xceed.Wpf.DataGrid { CustomItemContainerGenerator generator = this.CustomItemContainerGenerator; - // the CurrentContext is the master DataGridContext, and - // this one will never change + // the CurrentContext is the master DataGridContext, and this one will never change if( currentContext == this.DataGridContext ) - { return; - } object newCurrentItem = currentContext.CurrentItem; - // Try to get the new DataGridContext mathing the old one (containing - // the old CurrentItem). - DataGridContext newCurrentContext = this.UpdateCurrentContextRecursive( this.DataGridContext, - currentContext, - out newCurrentItem ); + // Try to get the new DataGridContext mathing the old one (containing the old CurrentItem). + DataGridContext newCurrentContext = this.UpdateCurrentContextRecursive( this.DataGridContext, currentContext, out newCurrentItem ); // If it none was found, affect the master DataGridContext if( newCurrentContext == null ) @@ -4754,66 +4849,284 @@ namespace Xceed.Wpf.DataGrid this.SetCurrentDataGridContextHelper( newCurrentContext ); // Set it as current using the old context CurrentItem, CurrentColumn - newCurrentContext.SetCurrent( newCurrentItem, null, null, currentContext.CurrentColumn, false, false, this.SynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.ThemeChanged ); + newCurrentContext.SetCurrent( newCurrentItem, null, null, currentContext.CurrentColumn, false, false, + this.SynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.ThemeChanged ); + } + } + + private DataGridContext UpdateCurrentContextRecursive( DataGridContext parentDataGridContext, DataGridContext oldCurrentDataGridContext, out object newCurrentItem ) + { + if( parentDataGridContext == null ) + { + newCurrentItem = null; + return null; + } + + foreach( DataGridContext childContext in parentDataGridContext.GetChildContexts() ) + { + if( childContext.SourceDetailConfiguration == oldCurrentDataGridContext.SourceDetailConfiguration ) + { + object oldCurrentItem = oldCurrentDataGridContext.CurrentItem; + + System.Data.DataView dataView = ItemsSourceHelper.TryGetDataViewFromDataGridContext( childContext ); + + System.Data.DataRowView oldCurrentDataRowView = oldCurrentItem as System.Data.DataRowView; + + if( ( dataView != null ) && ( oldCurrentDataRowView != null ) ) + { + System.Data.DataRow oldDataRow = oldCurrentDataRowView.Row; + + foreach( System.Data.DataRowView dataRowView in dataView ) + { + if( dataRowView.Row == oldDataRow ) + { + newCurrentItem = dataRowView; + return childContext; + } + } + } + else + { + if( childContext.Items.Contains( oldCurrentItem ) ) + { + newCurrentItem = oldCurrentItem; + return childContext; + } + } + } + + DataGridContext foundContext = this.UpdateCurrentContextRecursive( childContext, oldCurrentDataGridContext, out newCurrentItem ); + + if( foundContext != null ) + return foundContext; + } + + newCurrentItem = null; + return null; + } + + #endregion + + #region DRAG TO SELECT + + private AutoScrollManager AutoScrollManager + { + get + { + return m_autoScrollManager; + } + set + { + if( m_autoScrollManager != null ) + { + m_autoScrollManager.AutoScrolled -= this.OnAutoScrollManagerAutoScrolled; + } + + m_autoScrollManager = value; + + if( m_autoScrollManager != null ) + { + m_autoScrollManager.AutoScrolled += this.OnAutoScrollManagerAutoScrolled; + } + } + } + + private void OnPreviewMouseDown_DragToSelect( MouseButtonEventArgs e ) + { + if( !this.UseDragToSelectBehavior ) + return; + + if( e.LeftButton != MouseButtonState.Pressed ) + return; + + var source = e.OriginalSource as DependencyObject; + if( source == null ) + return; + + var container = DataGridControl.GetContainer( source ); + var itemContainer = container as IDataGridItemContainer; + if( itemContainer == null ) + return; + + var dataGridContext = DataGridControl.GetDataGridContext( container ); + if( ( dataGridContext == null ) || ( dataGridContext.DataGridControl != this ) ) + return; + + m_startDragSelection = false; + + if( container is Row ) + { + m_startDragSelection = ( DataGridVirtualizingPanel.GetItemIndex( container ) >= 0 ); + } + } + + private void OnMouseLeftButtonUp_DragToSelect( MouseButtonEventArgs e ) + { + this.AbortDragSelection(); + } + + private void OnLostMouseCapture_DragToSelect( MouseEventArgs e ) + { + this.AbortDragSelection(); + } + + private void OnMouseMove_DragToSelect( MouseEventArgs e ) + { + // Verify if the "Excel like drag selection" should be handled. + if( !this.UseDragToSelectBehavior ) + return; + + if( e.LeftButton != MouseButtonState.Pressed ) + return; + + if( !this.IsKeyboardFocusWithin ) + return; + + var autoScrollManager = this.AutoScrollManager; + if( autoScrollManager != null ) + { + m_startDragSelection = false; + + // This should happen only on the second mouse move after the mouse down. + // The mouse is capture so "MouseMove" and "ButtonUp" events can be handled outside the DataGridControl. + if( !this.IsMouseCaptured ) + { + this.CaptureMouse(); + } + + autoScrollManager.HandleMouseMove( e ); + e.Handled = this.SelectMouseOverElement(); } + // This should happen only on the first mouse move after the mouse down, if it was detected that DragSelection should be processed. + else if( m_startDragSelection ) + { + m_startDragSelection = false; + + // Before starting the AutoScrollManager, make sure all the conditions that apply in OnPreviewMouseDown_DragToSelect are still valid here. + var source = e.OriginalSource as DependencyObject; + if( source == null ) + return; + + var container = DataGridControl.GetContainer( source ); + var itemContainer = container as IDataGridItemContainer; + if( itemContainer == null ) + return; + + var dataGridContext = DataGridControl.GetDataGridContext( container ); + if( ( dataGridContext == null ) || ( dataGridContext.DataGridControl != this ) ) + return; + + autoScrollManager = new AutoScrollManager( this.ScrollViewer ); + autoScrollManager.Start(); + this.AutoScrollManager = autoScrollManager; + } + } + + private void OnAutoScrollManagerAutoScrolled( object sender, EventArgs e ) + { + Debug.Assert( this.UseDragToSelectBehavior ); + this.SelectMouseOverElement(); } - private DataGridContext UpdateCurrentContextRecursive( - DataGridContext parentDataGridContext, - DataGridContext oldCurrentDataGridContext, - out object newCurrentItem ) + private void AbortDragSelection() { - if( parentDataGridContext == null ) + var autoScrollManager = this.AutoScrollManager; + if( autoScrollManager != null ) { - newCurrentItem = null; - return null; + autoScrollManager.Stop(); + this.AutoScrollManager = null; + this.ReleaseMouseCapture(); } + } - foreach( DataGridContext childContext in parentDataGridContext.GetChildContexts() ) + private bool SelectMouseOverElement() + { + var itemsHost = this.ItemsHost; + var mousePosition = Mouse.GetPosition( itemsHost ); + var hitPosition = new Point(); + + var width = itemsHost.ActualWidth; + var height = itemsHost.ActualHeight; + + //Here, Since we are auto scrolling, the mouse position may be + // out of the bounds of the datagrid. Get the mouse's nearest row or cell. + hitPosition.Y = Math.Min( Math.Max( 0d, mousePosition.Y ), height - 1 ); + hitPosition.X = Math.Min( Math.Max( 0d, mousePosition.X ), width - 1 ); + + var targetItem = itemsHost.InputHitTest( hitPosition ) as DependencyObject; + if( targetItem == null ) + return false; + + var container = DataGridControl.GetContainer( targetItem ); + if( container == null ) + return false; + + var dataGridContext = DataGridControl.GetDataGridContext( container ); + if( ( dataGridContext == null ) || ( DataGridContext.DataGridControl != this ) ) + return false; + + var newPosition = default( SelectionRangePoint ); + + var row = container as Row; + if( row != null ) { - if( childContext.SourceDetailConfiguration == oldCurrentDataGridContext.SourceDetailConfiguration ) - { - object oldCurrentItem = oldCurrentDataGridContext.CurrentItem; + var sourceDataItemIndex = DataGridVirtualizingPanel.GetItemIndex( row ); + if( sourceDataItemIndex < 0 ) + return false; - System.Data.DataView dataView = - ItemsSourceHelper.TryGetDataViewFromDataGridContext( childContext ); + var columnIndex = -1; - System.Data.DataRowView oldCurrentDataRowView = oldCurrentItem as System.Data.DataRowView; + // Dont border finding the cell if we are not in cell selection mode. + if( this.SelectionUnit == DataGrid.SelectionUnit.Cell ) + { + var cell = targetItem as Cell; + if( ( cell == null ) || ( cell.ParentColumn.DataGridControl != this ) ) + { + cell = Cell.FindFromChild( this, targetItem ); + } - if( ( dataView != null ) && ( oldCurrentDataRowView != null ) ) + if( cell == null ) { - System.Data.DataRow oldDataRow = oldCurrentDataRowView.Row; + // If the cell is still null, It may be because the X mouse position was out of bounds + // an thus, we should take the first or last visible cell in screen + if( mousePosition.X >= 0d && mousePosition.X < itemsHost.Width ) + return false; - foreach( System.Data.DataRowView dataRowView in dataView ) - { - if( dataRowView.Row == oldDataRow ) - { - newCurrentItem = dataRowView; - return childContext; - } - } + var columnManager = dataGridContext.ColumnVirtualizationManager as TableViewColumnVirtualizationManagerBase; + if( columnManager == null ) + return false; + + var columns = columnManager.GetVisibleFieldNames(); + if( columns.Count <= 0 ) + return false; + + var index = ( mousePosition.X < 0 ) ? 0 : columns.Count - 1; + + columnIndex = dataGridContext.Columns[ columns[ index ] ].VisiblePosition; } else { - if( childContext.Items.Contains( oldCurrentItem ) ) - { - newCurrentItem = oldCurrentItem; - return childContext; - } + columnIndex = cell.ParentColumn.VisiblePosition; } } - DataGridContext foundContext = this.UpdateCurrentContextRecursive( childContext, oldCurrentDataGridContext, out newCurrentItem ); + var item = dataGridContext.GetItemFromContainer( row ); - if( foundContext != null ) - return foundContext; + newPosition = SelectionRangePoint.TryCreateRangePoint( dataGridContext, item, sourceDataItemIndex, columnIndex ); + } + else + { + return false; } - newCurrentItem = null; - return null; + if( newPosition == null ) + return false; + + m_selectionChangerManager.UpdateSelection( null, newPosition, true, false, SelectionManager.UpdateSelectionSource.MouseMove ); + return true; } - #endregion SELECTION/CURRENT + #endregion public override void OnApplyTemplate() { @@ -4837,7 +5150,7 @@ namespace Xceed.Wpf.DataGrid m_itemsHost = null; - Xceed.Wpf.DataGrid.Views.ViewBase view = this.GetView(); + Views.ViewBase view = this.GetView(); if( view.UseDefaultHeadersFooters ) { @@ -4854,28 +5167,28 @@ namespace Xceed.Wpf.DataGrid } } - public void ExpandGroup( CollectionViewGroup group ) + public bool ExpandGroup( CollectionViewGroup group ) { if( group == null ) throw new ArgumentNullException( "group" ); - this.DataGridContext.ExpandGroup( group ); + return this.DataGridContext.ExpandGroup( group ); } - public void CollapseGroup( CollectionViewGroup group ) + public bool CollapseGroup( CollectionViewGroup group ) { if( group == null ) throw new ArgumentNullException( "group" ); - this.DataGridContext.CollapseGroup( group ); + return this.DataGridContext.CollapseGroup( group ); } - public void ToggleGroupExpansion( CollectionViewGroup group ) + public bool ToggleGroupExpansion( CollectionViewGroup group ) { if( group == null ) throw new ArgumentNullException( "group" ); - this.DataGridContext.ToggleGroupExpansion( group ); + return this.DataGridContext.ToggleGroupExpansion( group ); } public bool IsGroupExpanded( CollectionViewGroup group ) @@ -4886,30 +5199,6 @@ namespace Xceed.Wpf.DataGrid return this.DataGridContext.IsGroupExpanded( group ); } - public void CollapseDetails( object dataItem ) - { - //This function will work only for master items. - //the DataGridContext and its generator will determine that the item is not present in the immediate structure - //and throw if the item passed is not a master item. - this.DataGridContext.CollapseDetails( dataItem ); - } - - public void ExpandDetails( object dataItem ) - { - //This function will work only for master items. - //the DataGridContext and its generator will determine that the item is not present in the immediate structure - //and throw if the item passed is not a master item. - this.DataGridContext.ExpandDetails( dataItem ); - } - - public void ToggleDetailExpansion( object dataItem ) - { - //This function will work only for master items. - //the DataGridContext and its generator will determine that the item is not present in the immediate structure - //and throw if the item passed is not a master item. - this.DataGridContext.ToggleDetailExpansion( dataItem ); - } - public bool AreDetailsExpanded( object dataItem ) { //This function will work only for master items. @@ -4917,11 +5206,6 @@ namespace Xceed.Wpf.DataGrid return this.DataGridContext.AreDetailsExpanded( dataItem ); } - internal DataGridContext GetChildContext( object parentItem, DetailConfiguration detailConfiguration ) - { - return this.DataGridContext.GetChildContext( parentItem, detailConfiguration ); - } - public DataGridContext GetChildContext( object parentItem, string relationName ) { return this.DataGridContext.GetChildContext( parentItem, relationName ); @@ -4965,10 +5249,59 @@ namespace Xceed.Wpf.DataGrid return this.DataGridContext.GetParentGroupFromItem( item ); } + public IDisposable DeferColumnsUpdate() + { + return this.DataGridContext.DeferColumnsUpdate(); + } + + public bool MoveColumnBefore( ColumnBase current, ColumnBase next ) + { + return this.DataGridContext.MoveColumnBefore( current, next ); + } + + public bool MoveColumnAfter( ColumnBase current, ColumnBase previous ) + { + return this.DataGridContext.MoveColumnAfter( current, previous ); + } + + public bool MoveColumnUnder( ColumnBase current, ColumnBase parent ) + { + return this.DataGridContext.MoveColumnUnder( current, parent ); + } + + [Obsolete( "MoveMergedColumn is obsolete. Use MoveColumnUnder instead." )] + [Browsable( false )] + [EditorBrowsable( EditorBrowsableState.Never )] + public void MoveMergedColumn( ColumnBase columnToMove, ColumnBase parentMergedColumn ) + { + if( !this.MoveColumnUnder( columnToMove, parentMergedColumn ) ) + throw new InvalidOperationException( "Failed to move the column." ); + } + + [Obsolete( "MoveMergedColumn is obsolete. Use MoveColumnUnder instead." )] + [Browsable( false )] + [EditorBrowsable( EditorBrowsableState.Never )] + public void MoveMergedColumn( string columnToMove, string parentMergedColumn ) + { + var level = -1; + var parentColumn = default( ColumnBase ); + + if( level == -1 ) + throw new ArgumentException( "An attempt was made to use a column that is not part of a MergedHeader.", "parentMergedColumn" ); + + ColumnBase childColumn = null; + childColumn = this.Columns[ columnToMove ]; + if( childColumn == null ) + throw new ArgumentException( "An attempt was made to move an invalid child column to a parent merged column.", "childColumn" ); + + if( !this.MoveColumnUnder( childColumn, parentColumn ) ) + throw new InvalidOperationException( "Failed to move the column." ); + } + protected override Size MeasureOverride( Size constraint ) { //By default the measure pass must not be delayed, or if the grid is already loaded or if we are printing. - if( ( !this.DeferInitialLayoutPass ) || ( this.IsLoaded ) || ( this.IsPrinting ) || ( !m_isFirstTimeLoaded ) ) + if( ( !this.DeferInitialLayoutPass ) || ( this.IsLoaded )|| ( !m_isFirstTimeLoaded ) ) return base.MeasureOverride( constraint ); return this.GetStartUpSize( constraint ); @@ -4977,7 +5310,7 @@ namespace Xceed.Wpf.DataGrid protected override Size ArrangeOverride( Size arrangeBounds ) { //By default the measure pass must not be delayed, or if the grid is already loaded or if we are printing. - if( ( !this.DeferInitialLayoutPass ) || ( this.IsLoaded ) || ( this.IsPrinting ) || ( !m_isFirstTimeLoaded ) ) + if( ( !this.DeferInitialLayoutPass ) || ( this.IsLoaded ) || ( !m_isFirstTimeLoaded ) ) return base.ArrangeOverride( arrangeBounds ); return arrangeBounds; @@ -5005,14 +5338,14 @@ namespace Xceed.Wpf.DataGrid this.ForceFocus( this.ScrollViewer ); } - IDataGridItemContainer dataGridItemContainer = element as IDataGridItemContainer; - Row row = element as Row; + var dataGridItemContainer = element as IDataGridItemContainer; + var row = element as Row; // Only preserve ContainerSizeState if necessary if( !this.IsBoundToDataGridVirtualizingCollectionViewBase && this.ViewPreservesContainerSize ) { - DataGridContext dataGridContext = DataGridControl.GetDataGridContext( element ); + var dataGridContext = DataGridControl.GetDataGridContext( element ); //Save the size state of the container (this will do nothing if no size has been set on the item ). dataGridContext.SaveContainerSizeState( item, feContainer ); @@ -5022,7 +5355,7 @@ namespace Xceed.Wpf.DataGrid // calling ClearContainer on a Row inside a HeaderFooterItem. // HeaderFooterItem implements IDataGridItemContainer and we call // ClearContainer on it if not null. - HeaderFooterItem hfi = element as HeaderFooterItem; + var hfi = element as HeaderFooterItem; // If element is a HeaderFooterItem, then it cannot be a Row if( hfi != null ) @@ -5036,17 +5369,15 @@ namespace Xceed.Wpf.DataGrid //cancel edit if applicable and preserve state of the row. if( row.IsBeingEdited ) { - RowState oldRowEditionState = m_currentRowInEditionState.Clone(); + var oldRowEditionState = m_currentRowInEditionState.Clone(); + var oldColumnsStates = new Dictionary(); - Dictionary oldColumnsStates = new Dictionary(); - - Debug.Assert( item == m_currentItemInEdition, "The current item being edited on the DataGridControl differs from the one of the currently edited container." ); + //Debug.Assert( item == m_currentItemInEdition, "The current item being edited on the DataGridControl differs from the one of the currently edited container." ); // We can use row because there is only one row in edition in the DataGridControl foreach( Cell cell in row.CreatedCells ) { - ColumnBase parentColumn = cell.ParentColumn; - + var parentColumn = cell.ParentColumn; if( parentColumn == null ) continue; @@ -5082,8 +5413,7 @@ namespace Xceed.Wpf.DataGrid foreach( ColumnBase column in oldColumnsStates.Keys ) { - CellState oldCellState = oldColumnsStates[ column ]; - column.CurrentRowInEditionCellState = oldCellState; + column.CurrentRowInEditionCellState = oldColumnsStates[ column ]; } // Though the row state is preserved, the DataGridControl is not in editing anymore. @@ -5116,8 +5446,7 @@ namespace Xceed.Wpf.DataGrid dataGridItemContainer.ClearContainer(); } - UIElement uiElement = element as UIElement; - + var uiElement = element as UIElement; if( ( uiElement != null ) && ( ( uiElement.IsKeyboardFocusWithin ) || ( uiElement.IsKeyboardFocused ) ) ) { // If the element we are cleaning up contains the focus, we ensure to refocus the ScrollViewer to have @@ -5130,8 +5459,7 @@ namespace Xceed.Wpf.DataGrid { base.PrepareContainerForItemOverride( element, item ); - //this is specific to the DataRows from the Original items list... do not want to do that in the - //Row.PrepareContainer() + //this is specific to the DataRows from the Original items list... do not want to do that in the Row.PrepareContainer() IDataGridItemContainer dataGridItemContainer = element as IDataGridItemContainer; Row row = element as Row; @@ -5139,7 +5467,6 @@ namespace Xceed.Wpf.DataGrid DataGridContext dataGridContext = DataGridControl.GetDataGridContext( element ); Debug.Assert( dataGridContext != null ); - if( dataGridItemContainer != null ) { dataGridItemContainer.PrepareContainer( dataGridContext, item ); @@ -5203,8 +5530,7 @@ namespace Xceed.Wpf.DataGrid } else { - //this condition is for Rows that are recycled from an environment where they had - //and item container style to one that doesn't... + //this condition is for Rows that are recycled from an environment where they had and item container style to one that doesn't... if( row.ReadLocalValue( Row.StyleProperty ) != DependencyProperty.UnsetValue ) { row.ClearValue( Row.StyleProperty ); @@ -5220,8 +5546,7 @@ namespace Xceed.Wpf.DataGrid //as such, I will re-determine if the item is a Row ( this time digging beyond HeaderFooterItem // Only restore ContainerSizeState if necessary - if( !this.IsBoundToDataGridVirtualizingCollectionViewBase - && this.ViewPreservesContainerSize ) + if( !this.IsBoundToDataGridVirtualizingCollectionViewBase && this.ViewPreservesContainerSize ) { //Restore the Size of the item (if there was some special size assigned to the item container previously dataGridContext.RestoreContainerSizeState( item, element as FrameworkElement ); @@ -5240,7 +5565,7 @@ namespace Xceed.Wpf.DataGrid //Only perform the BringItemIntoView if the item focused is within the host panel! if( ScrollViewerHelper.IsFocusInElement( this.ItemsHost as FrameworkElement ) ) { - DataGridContext currentDataGridContext = this.CurrentContext; + var currentDataGridContext = this.CurrentContext; //ensure that the key pressed is a Keyboard Navigation key switch( e.Key ) @@ -5258,40 +5583,44 @@ namespace Xceed.Wpf.DataGrid case Key.Space: { - DependencyObject originalSource = e.OriginalSource as DependencyObject; - - FrameworkElement element = CustomItemContainerGenerator.FindContainerFromChildOrRowSelectorOrSelf( this, originalSource ); + var originalSource = e.OriginalSource as DependencyObject; + if( originalSource == null ) + break; - Row row = element as Row; - SelectionRangePoint newPosition = null; + var container = DataGridControl.GetContainer( originalSource ); + if( container == null ) + break; - if( ( row != null ) && ( !row.IsBeingEdited ) ) - { - DataGridContext newDataGridContext = DataGridControl.GetDataGridContext( row ); + var dataGridContext = DataGridControl.GetDataGridContext( container ); + if( ( dataGridContext == null ) || ( dataGridContext.DataGridControl != this ) ) + break; - if( newDataGridContext != null ) - { - int sourceDataItemIndex = DataGridVirtualizingPanel.GetItemIndex( row ); - object item = newDataGridContext.GetItemFromContainer( row ); - Cell cell = originalSource as Cell; + var row = container as Row; + var newPosition = default( SelectionRangePoint ); - if( ( cell == null ) || ( cell.ParentColumn.DataGridControl != this ) ) - { - cell = Cell.FindFromChild( this, originalSource ); - } + if( row != null ) + { + if( row.IsBeingEdited ) + break; - int columnIndex = ( cell == null ) ? -1 : cell.ParentColumn.VisiblePosition; + var cell = Cell.FindFromChildOrSelf( this, originalSource ); + var item = dataGridContext.GetItemFromContainer( row ); + var itemIndex = DataGridVirtualizingPanel.GetItemIndex( row ); + var column = ( cell != null ) ? cell.ParentColumn : null; + var columnIndex = ( column != null ) ? column.VisiblePosition : -1; - newPosition = new SelectionRangePoint( newDataGridContext, item, sourceDataItemIndex, columnIndex ); - } + newPosition = SelectionRangePoint.TryCreateRangePoint( dataGridContext, item, itemIndex, columnIndex ); + } + else + { + break; } if( newPosition != null ) { - var oldPosition = SelectionRangePoint.TryCreateFromCurrent( this.CurrentContext ); + var oldPosition = SelectionRangePoint.TryCreateFromCurrent( DataGridControl.GetDataGridContext( container ) ); - m_selectionChangerManager.UpdateSelection( oldPosition, newPosition, true, - false, SelectionManager.UpdateSelectionSource.SpaceDown ); + m_selectionChangerManager.UpdateSelection( oldPosition, newPosition, true, false, SelectionManager.UpdateSelectionSource.SpaceDown ); e.Handled = true; } @@ -5375,11 +5704,10 @@ namespace Xceed.Wpf.DataGrid { if( m_mouseDownUpdateSelectionSource == null ) { - m_mouseDownUpdateSelectionSource = this.SelectionChangerManager.PushUpdateSelectionSource( - SelectionManager.UpdateSelectionSource.MouseDown ); + m_mouseDownUpdateSelectionSource = this.SelectionChangerManager.PushUpdateSelectionSource( SelectionManager.UpdateSelectionSource.MouseDown ); } - ColumnBase currentColumn = this.CurrentColumn; + var currentColumn = this.CurrentColumn; m_mouseDownSelectionRangePoint = SelectionRangePoint.TryCreateFromCurrent( this.CurrentContext ); @@ -5388,20 +5716,29 @@ namespace Xceed.Wpf.DataGrid if( e.Handled ) return; - DataGridContext oldDataGridContext = this.CurrentContext; - Row oldRow = ( oldDataGridContext == null ) ? null : oldDataGridContext.CurrentRow; + var oldDataGridContext = this.CurrentContext; + var oldRow = ( oldDataGridContext == null ) ? null : oldDataGridContext.CurrentRow; + + var source = e.OriginalSource as DependencyObject; + if( source == null ) + return; + + var container = DataGridControl.GetContainer( source ); + if( container == null ) + return; + + var newDataGridContext = DataGridControl.GetDataGridContext( container ); + if( ( newDataGridContext == null ) || ( newDataGridContext.DataGridControl != this ) ) + return; - UIElement newContainer = CustomItemContainerGenerator.FindContainerFromChildOrRowSelectorOrSelf( - this, e.OriginalSource as DependencyObject ); + var newRow = Row.FromContainer( container ); - Row newRow = Row.FromContainer( newContainer ); + this.OnPreviewMouseDown_DragToSelect( e ); - // testing newContainer == null is a way to not end edition when moving - // the scroll bar around. - if( ( oldRow == null ) || ( newContainer == null ) || ( !oldRow.IsBeingEdited ) || ( newRow == oldRow ) ) + if( ( oldRow == null ) || ( !oldRow.IsBeingEdited ) || ( newRow == oldRow ) ) return; - ColumnBase oldCurrentColumn = oldDataGridContext.CurrentColumn; + var oldCurrentColumn = oldDataGridContext.CurrentColumn; bool mouseDownHandled; Row newFocusedRow; @@ -5411,8 +5748,7 @@ namespace Xceed.Wpf.DataGrid { // If the source is reset during the EndEdit, we move the focus temporarely on the ScrollViewer to prevent some issue // when the EndEdit cause a Reset (The ScrollViewer was trying to bring into view the old editing Cell). - bool focused = this.ForceFocus( this.ScrollViewer ); - + var focused = this.ForceFocus( this.ScrollViewer ); if( !focused ) return; @@ -5425,16 +5761,14 @@ namespace Xceed.Wpf.DataGrid this.UpdateLayout(); IInputElement visualHit = this.InputHitTest( e.GetPosition( this ) ); - mouseDownHandled = ( visualHit == null ) - || ( !object.ReferenceEquals( visualHit, e.OriginalSource ) ); + mouseDownHandled = ( visualHit == null ) || ( !object.ReferenceEquals( visualHit, e.OriginalSource ) ); newFocusedRow = newRow; newFocusedColumn = currentColumn; } } catch( DataGridException ) { - // We swallow exception if it occurs because of a validation error or Cell was read-only or - // any other GridException. + // We swallow exception if it occurs because of a validation error or Cell was read-only or any other GridException. mouseDownHandled = true; newFocusedRow = oldRow; newFocusedColumn = oldCurrentColumn; @@ -5467,44 +5801,45 @@ namespace Xceed.Wpf.DataGrid return; var source = e.OriginalSource as DependencyObject; + if( source == null ) + return; - FrameworkElement element = CustomItemContainerGenerator.FindContainerFromChildOrRowSelectorOrSelf( this, source ); + var container = DataGridControl.GetContainer( source ); + if( ( container == null ) || ( !container.IsKeyboardFocused && !container.IsKeyboardFocusWithin ) ) + return; - if( element == null || ( !element.IsKeyboardFocused && !element.IsKeyboardFocusWithin ) ) + var dataGridContext = DataGridControl.GetDataGridContext( container ); + if( ( dataGridContext == null ) || ( dataGridContext.DataGridControl != this ) ) return; - var row = element as Row; - SelectionRangePoint newPosition = null; - bool rowIsBeingEdited = false; + var row = container as Row; + var newPosition = default( SelectionRangePoint ); + var rowIsBeingEdited = false; if( row != null ) { - var dataGridContext = DataGridControl.GetDataGridContext( row ); - if( dataGridContext == null ) - return; - var cell = Cell.FindFromChildOrSelf( this, source ); if( ( cell != null ) && ( this.SelectionUnit == SelectionUnit.Cell ) && ( !cell.IsKeyboardFocused ) && ( !cell.IsKeyboardFocusWithin ) ) return; - var itemIndex = DataGridVirtualizingPanel.GetItemIndex( row ); var item = dataGridContext.GetItemFromContainer( row ); - + var itemIndex = DataGridVirtualizingPanel.GetItemIndex( row ); var column = ( cell != null ) ? cell.ParentColumn : null; var columnIndex = ( column != null ) ? column.VisiblePosition : -1; - // If we have an error during the EndEdit that prevent the PreviewMouseDown from occuring - // (since we put e.Handled = true if an exception occurs), + // If we have an error during the EndEdit that prevent the PreviewMouseDown from occuring (since we put e.Handled = true if an exception occurs), // the PreviewMouseUp will not occur, so it is safe to call UpdateSelection(). - newPosition = new SelectionRangePoint( dataGridContext, item, itemIndex, columnIndex ); + newPosition = SelectionRangePoint.TryCreateRangePoint( dataGridContext, item, itemIndex, columnIndex ); rowIsBeingEdited = row.IsBeingEdited; } + else + { + return; + } if( newPosition != null ) { - m_selectionChangerManager.UpdateSelection( - m_mouseDownSelectionRangePoint, newPosition, true, rowIsBeingEdited, - SelectionManager.UpdateSelectionSource.MouseUp ); + m_selectionChangerManager.UpdateSelection( m_mouseDownSelectionRangePoint, newPosition, true, rowIsBeingEdited, SelectionManager.UpdateSelectionSource.MouseUp ); } } @@ -5533,7 +5868,7 @@ namespace Xceed.Wpf.DataGrid if( e.Handled || m_inhibitPreviewGotKeyboardFocus.IsSet ) return; - DependencyObject newFocus = e.NewFocus as DependencyObject; + var newFocus = e.NewFocus as DependencyObject; if( this.NavigationBehavior == NavigationBehavior.None ) { @@ -5547,9 +5882,9 @@ namespace Xceed.Wpf.DataGrid if( ( newFocus == this ) || ( newFocus == this.ScrollViewer ) ) { - DataGridContext currentDataGridContext = this.CurrentContext; - object internalCurrentItem = currentDataGridContext.InternalCurrentItem; - UIElement itemUIElement = null; + var currentDataGridContext = this.CurrentContext; + var internalCurrentItem = currentDataGridContext.InternalCurrentItem; + var itemUIElement = default( UIElement ); if( ( internalCurrentItem == null ) && ( currentDataGridContext.Items.Count > 0 ) ) { @@ -5560,7 +5895,8 @@ namespace Xceed.Wpf.DataGrid { using( this.InhibitSetFocus() ) { - currentDataGridContext.SetCurrent( internalCurrentItem, null, 0, currentDataGridContext.CurrentColumn, false, false, this.SynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.FocusChanged ); + currentDataGridContext.SetCurrent( internalCurrentItem, null, 0, currentDataGridContext.CurrentColumn, false, false, this.SynchronizeSelectionWithCurrent, + AutoScrollCurrentItemSourceTriggers.FocusChanged ); } } } @@ -5571,16 +5907,16 @@ namespace Xceed.Wpf.DataGrid itemUIElement = currentDataGridContext.GetContainerFromItem( internalCurrentItem ) as UIElement; // Special case when the previous element with the focus is now collapsed, the focus must be moved to the ScrollViewer, so the grid is kept focusable. - bool focusScrollViewer = ( itemUIElement == null ); + var focusScrollViewer = ( itemUIElement == null ); if( !focusScrollViewer ) { - HeaderFooterItem headerFooterItem = itemUIElement as HeaderFooterItem; + var headerFooterItem = itemUIElement as HeaderFooterItem; if( headerFooterItem != null ) { focusScrollViewer = headerFooterItem.Visibility == Visibility.Collapsed; if( !focusScrollViewer ) { - UIElement container = headerFooterItem.Container as UIElement; + var container = headerFooterItem.Container as UIElement; if( container != null ) { focusScrollViewer = container.Visibility == Visibility.Collapsed; @@ -5616,53 +5952,51 @@ namespace Xceed.Wpf.DataGrid } // If the focus was in a popup menu, we don't want to change the selection, so we consider the focus to be outside the grid in that situation. - bool oldFocusWasInTheGrid = ( e.OldFocus != null ) && ( TreeHelper.IsDescendantOf( e.OldFocus as DependencyObject, this, false ) ); - DataGridContext oldCurrentDataGridContext = this.CurrentContext; + var oldFocusWasInTheGrid = ( e.OldFocus != null ) && ( TreeHelper.IsDescendantOf( e.OldFocus as DependencyObject, this, false ) ); + var oldCurrentDataGridContext = this.CurrentContext; + var oldRow = default( Row ); + var oldPosition = default( SelectionRangePoint ); - Row oldRow = null; - SelectionRangePoint oldPosition = null; if( oldCurrentDataGridContext != null ) { oldRow = oldCurrentDataGridContext.CurrentRow; oldPosition = SelectionRangePoint.TryCreateFromCurrent( oldCurrentDataGridContext ); + m_oldColumn = oldCurrentDataGridContext.CurrentCell != null ? new WeakReference( oldCurrentDataGridContext.CurrentCell.ParentColumn ) : m_oldColumn; } - FrameworkElement newContainer = CustomItemContainerGenerator.FindContainerFromChildOrRowSelectorOrSelf( this, newFocus ); - - DataGridContext newDataGridContext = ( newContainer == null ) ? null : DataGridControl.GetDataGridContext( newContainer ); - - Row newRow = Row.FromContainer( newContainer ); - Cell newCell = newFocus as Cell; + var newContainer = this.GetLocalContainer( newFocus ); + var newDataGridContext = ( newContainer == null ) ? null : DataGridControl.GetDataGridContext( newContainer ); + var newRow = Row.FromContainer( newContainer ); + var newCell = newFocus as Cell; if( ( newCell == null ) || ( newCell.ParentColumn.DataGridControl != this ) ) { newCell = Cell.FindFromChild( this, newFocus ); } - ColumnBase newColumn = ( newCell == null ) ? null : newCell.ParentColumn; - object item = ( newContainer == null ) ? null : newDataGridContext.GetItemFromContainer( newContainer ); - bool containerChangedDuringEndEdit = false; + var newColumn = ( newCell == null ) ? null : newCell.ParentColumn; + var item = ( newContainer == null ) ? null : newDataGridContext.GetItemFromContainer( newContainer ); + var containerChangedDuringEndEdit = false; // Prevent the focus to be moved during the EndEdit since we are changing focus at the moment using( this.InhibitSetFocus() ) { if( ( oldRow != null ) && ( oldRow.IsBeingEdited ) ) { - Cell oldCell = ( oldCurrentDataGridContext == null ) ? null : oldCurrentDataGridContext.CurrentCell; + var oldCell = ( oldCurrentDataGridContext == null ) ? null : oldCurrentDataGridContext.CurrentCell; if( oldRow != newRow ) { try { - FrameworkElement previousNewContainer = newContainer; + var previousNewContainer = newContainer; oldRow.EndEdit(); - // We must refetch the container for the current item in case EndEdit triggers a reset on the CustomItemContainerGenerator + // We must refetch the container for the current item in case EndEdit triggers a reset on the CustomItemContainerGenerator // and remap this item to a container other than the one previously fetched this.UpdateLayout(); newContainer = ( item == null ) ? null : newDataGridContext.GetContainerFromItem( item ) as FrameworkElement; - newRow = Row.FromContainer( newContainer ); newCell = ( newRow == null ) ? null : newRow.Cells[ newColumn ]; @@ -5673,7 +6007,7 @@ namespace Xceed.Wpf.DataGrid } else { - // If the newFocus is not in the the grid anymore, stop the focus. + // If the newFocus is not in the grid anymore, stop the focus. if( DataGridControl.GetDataGridContext( newFocus ) == null ) { e.Handled = true; @@ -5717,16 +6051,15 @@ namespace Xceed.Wpf.DataGrid try { - Cell oldFocusedCell = e.OldFocus as Cell; - UIElement newFocusedElement = e.NewFocus as UIElement; + var oldFocusedCell = e.OldFocus as Cell; + var newFocusedElement = e.NewFocus as UIElement; // here we check if the oldFocus is the parent of the new focused element because the OnPreviewGotKeyboardFocus // is called twice if it's the case which give twice the focus and then endsup unselecting the element during the mouseUp // because during the second updateSelection, the element is already contained then m_updateSelectionOnNextMouseUp set to true - bool isNewFocusParentTheOldFocusedCell = ( ( oldFocusedCell != null ) && ( newFocusedElement != null ) ) ? - ( oldFocusedCell != Cell.FindFromChild( this, newFocusedElement ) ) : true; - - int sourceDataItemIndex = DataGridVirtualizingPanel.GetItemIndex( newRow ); + var isNewFocusParentTheOldFocusedCell = ( ( oldFocusedCell != null ) && ( newFocusedElement != null ) ) ? + ( oldFocusedCell != Cell.FindFromChild( this, newFocusedElement ) ) : true; + var sourceDataItemIndex = DataGridVirtualizingPanel.GetItemIndex( newRow ); // newCell != newFocus is in fact a way to test if newFocus is a child of the cell. if( ( newFocus != null ) && ( newCell != newFocus ) && ( !newCell.IsBeingEdited ) && ( newCell.IsCellEditorDisplayed ) ) @@ -5741,11 +6074,10 @@ namespace Xceed.Wpf.DataGrid if( isNewFocusParentTheOldFocusedCell ) { - bool rowIsBeingEditedAndCurrentRowNotChanged = this.IsRowBeingEditedAndCurrentRowNotChanged( newRow, oldRow ); + var rowIsBeingEditedAndCurrentRowNotChanged = this.IsRowBeingEditedAndCurrentRowNotChanged( newRow, oldRow ); var newPosition = SelectionRangePoint.TryCreateRangePoint( newDataGridContext, item, sourceDataItemIndex, newCell.ParentColumn.VisiblePosition ); - m_selectionChangerManager.UpdateSelection( oldPosition, newPosition, oldFocusWasInTheGrid, - rowIsBeingEditedAndCurrentRowNotChanged, null ); + m_selectionChangerManager.UpdateSelection( oldPosition, newPosition, oldFocusWasInTheGrid, rowIsBeingEditedAndCurrentRowNotChanged, null ); } } catch( DataGridException ) @@ -5770,22 +6102,57 @@ namespace Xceed.Wpf.DataGrid try { - ColumnBase currentColumn = null; + var currentColumn = default( ColumnBase ); // The current column may need to be propagated, unless the focus is being moved to a GroupHeaderControl - if( ( this.NavigationBehavior == NavigationBehavior.CellOnly ) && !( item is GroupHeaderFooterItem ) ) + // Special case for a row that is always set to NavigationBehavior.CellOnly (like FilterRow), as it needs a current column for the navigation to work propertly. + if( ( ( this.NavigationBehavior == NavigationBehavior.CellOnly ) || ( newRow.NavigationBehavior == NavigationBehavior.CellOnly ) ) + && !( item is GroupHeaderFooterItem ) ) { - currentColumn = newDataGridContext.CurrentColumn; + if( ( newDataGridContext != oldCurrentDataGridContext ) && this.AreDetailsFlatten ) + { + currentColumn = newDataGridContext.GetMatchingColumn( oldCurrentDataGridContext, m_oldColumn.Target as ColumnBase ); + } + + if( currentColumn == null ) + { + currentColumn = newDataGridContext.CurrentColumn; + } //if there is no current column, if( currentColumn == null ) { - //then use the first visible column - ReadOnlyObservableCollection columns = newDataGridContext.VisibleColumns; + //Check what was the last currentColumn before navigating in Row mode, in the case it's navigating again towards a cell (as for the FilterRow for instance). + var oldColumn = m_oldColumn.Target as ColumnBase; + if( ( oldColumn != null ) && ( newDataGridContext == oldCurrentDataGridContext ) ) + { + var fixedCellPanel = newRow.CellsHostPanel as FixedCellPanel; + if( fixedCellPanel != null ) + { + var cell = default( Cell ); + var virtualizingCellCollection = fixedCellPanel.ParentRowCells; + if( virtualizingCellCollection.TryGetBindedCell( oldColumn, out cell ) ) + { + currentColumn = oldColumn; + } + } + } + } + //If there is no last currentColumn, or it is not available for navigation. + if( currentColumn == null ) + { + //Then use the first visible column + var columns = newDataGridContext.VisibleColumns; if( columns.Count > 0 ) { - int firstFocusableColumn = NavigationHelper.GetFirstVisibleFocusableColumnIndex( newDataGridContext, newRow ); + //First try to find the first navigable column that is visible in the viewport. + var firstFocusableColumn = NavigationHelper.GetFirstVisibleFocusableInViewportColumnIndex( newDataGridContext, newRow ); + if( firstFocusableColumn == -1 ) + { + //If none is found, find the first navigable one. This will make the grid scroll if one is found, since it's currently out-of-view. + firstFocusableColumn = NavigationHelper.GetFirstVisibleFocusableColumnIndex( newDataGridContext, newRow ); + } if( firstFocusableColumn < 0 ) throw new DataGridException( "Trying to edit while no cell is focusable. ", this ); @@ -5823,13 +6190,11 @@ namespace Xceed.Wpf.DataGrid newDataGridContext.SetCurrent( item, newRow, sourceDataItemIndex, currentColumn, true, true, false, AutoScrollCurrentItemSourceTriggers.FocusChanged ); } - int columnIndex = ( currentColumn == null ) ? -1 : currentColumn.VisiblePosition; - - bool rowIsBeingEditedAndCurrentRowNotChanged = this.IsRowBeingEditedAndCurrentRowNotChanged( newRow, oldRow ); + var columnIndex = ( currentColumn == null ) ? -1 : currentColumn.VisiblePosition; + var rowIsBeingEditedAndCurrentRowNotChanged = this.IsRowBeingEditedAndCurrentRowNotChanged( newRow, oldRow ); var newPosition = SelectionRangePoint.TryCreateRangePoint( newDataGridContext, item, sourceDataItemIndex, columnIndex ); - m_selectionChangerManager.UpdateSelection( oldPosition, newPosition, oldFocusWasInTheGrid, - rowIsBeingEditedAndCurrentRowNotChanged, null ); + m_selectionChangerManager.UpdateSelection( oldPosition, newPosition, oldFocusWasInTheGrid, rowIsBeingEditedAndCurrentRowNotChanged, null ); } catch( DataGridException ) { @@ -5839,14 +6204,11 @@ namespace Xceed.Wpf.DataGrid return; } - if( newContainer != null ) + if( newContainer is HeaderFooterItem ) { - HeaderFooterItem headerFooterItem = newContainer as HeaderFooterItem; - - if( headerFooterItem == null ) - return; + var headerFooterItem = ( HeaderFooterItem )newContainer; - IDisposable inhibitSetFocus = null; + var inhibitSetFocus = default( IDisposable ); if( !containerChangedDuringEndEdit ) { @@ -5856,15 +6218,15 @@ namespace Xceed.Wpf.DataGrid try { SelectionRangePoint newPosition; - ColumnBase currentColumn = newDataGridContext.CurrentColumn; + + var currentColumn = newDataGridContext.CurrentColumn; newDataGridContext.SetCurrent( item, null, -1, currentColumn, true, true, false, AutoScrollCurrentItemSourceTriggers.FocusChanged ); - int columnIndex = ( currentColumn == null ) ? -1 : currentColumn.VisiblePosition; + var columnIndex = ( currentColumn == null ) ? -1 : currentColumn.VisiblePosition; newPosition = SelectionRangePoint.TryCreateRangePoint( newDataGridContext, item, -1, columnIndex ); - m_selectionChangerManager.UpdateSelection( oldPosition, newPosition, - oldFocusWasInTheGrid, false, null ); + m_selectionChangerManager.UpdateSelection( oldPosition, newPosition, oldFocusWasInTheGrid, false, null ); } catch( DataGridException ) { @@ -5898,6 +6260,15 @@ namespace Xceed.Wpf.DataGrid if( e.Handled ) return; + + this.OnMouseLeftButtonUp_DragToSelect( e ); + } + + protected override void OnLostMouseCapture( MouseEventArgs e ) + { + base.OnLostMouseCapture( e ); + + this.OnLostMouseCapture_DragToSelect( e ); } protected override void OnMouseMove( MouseEventArgs e ) @@ -5906,11 +6277,15 @@ namespace Xceed.Wpf.DataGrid if( e.Handled ) return; + + this.OnMouseMove_DragToSelect( e ); } - protected override AutomationPeer OnCreateAutomationPeer() + + protected override void OnPropertyChanged( DependencyPropertyChangedEventArgs e ) { - return new DataGridControlAutomationPeer( this ); + base.OnPropertyChanged( e ); + this.OnPropertyChanged( e.Property.Name ); } internal static object GetFixedItemFromContainer( DependencyObject container ) @@ -5975,6 +6350,9 @@ namespace Xceed.Wpf.DataGrid internal void ClearItemContainer( DependencyObject container, object item ) { + // For performance reason, it is useless to clear the ContainerProperty. The value is set in DataGridControl.PrepareItemContainer and it contains the + // container itself. Clearing it here to set it back later is pointless. Furthermore, setting and clearing the property cost more than usual since the + // DependencyProperty is inherited. To determine if the container is in use, the DataGridControl.IsContainerPrepared attached property should be use instead. //DataGridControl.ClearContainer( container ); DataGridControl.ClearIsContainerPrepared( container ); this.ClearContainerForItemOverride( container, item ); @@ -5987,8 +6365,7 @@ namespace Xceed.Wpf.DataGrid if( container != null ) { - // Set a local value for containers to ensure the - // DefaultStyleKey is correctly applied on this container + // Set a local value for containers to ensure the DefaultStyleKey is correctly applied on this container container.SetValue( DataGridControl.ParentDataGridControlPropertyKey, this ); } @@ -6093,34 +6470,15 @@ namespace Xceed.Wpf.DataGrid this.SetValue( ParentDataGridControlPropertyKey, null ); } - internal void QueueDataGridContextPeerChlidrenRefresh( DataGridContext dataGridContext ) - { - if( dataGridContext.Peer == null ) - return; - - if( m_dataGridContextToRefreshPeerChlidren == null ) - { - m_dataGridContextToRefreshPeerChlidren = new HashSet(); - m_dataGridContextToRefreshPeerChlidren.Add( dataGridContext ); - } - else - { - if( !m_dataGridContextToRefreshPeerChlidren.Contains( dataGridContext ) ) - { - m_dataGridContextToRefreshPeerChlidren.Add( dataGridContext ); - } - } - } - internal void SynchronizeForeignKeyConfigurations() { - ForeignKeyConfiguration.UpdateColumnsForeignKeyConfigurations( - this.Columns.FieldNameToColumnDictionary, - this.ItemsSource, - this.DataGridContext.ItemsSourceFieldDescriptors, - this.AutoCreateForeignKeyConfigurations ); + ForeignKeyConfiguration.UpdateColumnsForeignKeyConfigurations( this.Columns, + this.ItemsSource, + m_itemsSourcePropertyDescriptions, + this.AutoCreateForeignKeyConfigurations ); } + private static bool IsRemoveAllowedForDeleteCommand( IList list ) { // If the list has a fixed sized or if it's read only, we won't allow remove. @@ -6189,6 +6547,7 @@ namespace Xceed.Wpf.DataGrid } collection.Clear(); + } private static void RefreshFixedHeaderFooter( DataGridControl dataGrid, Panel targetPanel, ObservableCollection collection ) @@ -6227,6 +6586,7 @@ namespace Xceed.Wpf.DataGrid targetPanel.Children.Add( control ); } + } private void ReapplyTemplate() @@ -6265,6 +6625,37 @@ namespace Xceed.Wpf.DataGrid return rowIsBeingEditedAndCurrentRowNotChanged; } + private FrameworkElement GetLocalContainer( DependencyObject container ) + { + if( container == null ) + return null; + + var candidate = DataGridControl.GetContainer( container ); + while( candidate != null ) + { + if( ( candidate is IDataGridItemContainer ) && ( candidate is FrameworkElement ) ) + { + var dataGridContext = DataGridControl.GetDataGridContext( candidate ); + if( dataGridContext == null ) + break; + + var dataGridControl = dataGridContext.DataGridControl; + if( dataGridControl == this ) + return ( FrameworkElement )candidate; + + candidate = dataGridControl; + } + + var parent = TreeHelper.GetParent( candidate ); + if( parent == null ) + break; + + candidate = DataGridControl.GetContainer( parent ); + } + + return null; + } + private Size GetStartUpSize( Size constraint ) { double width = this.Width; @@ -6318,8 +6709,16 @@ namespace Xceed.Wpf.DataGrid protected virtual void OnNotifyPropertyChanged( PropertyChangedEventArgs e ) { - if( this.PropertyChanged != null ) - this.PropertyChanged( this, e ); + var handler = this.PropertyChanged; + if( handler == null ) + return; + + handler.Invoke( this, e ); + } + + private void OnPropertyChanged( string propertyName ) + { + this.OnNotifyPropertyChanged( new PropertyChangedEventArgs( propertyName ) ); } #endregion @@ -6328,60 +6727,57 @@ namespace Xceed.Wpf.DataGrid bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) { - if( managerType == typeof( RootGroupChangedEventManager ) ) + return this.OnReceiveWeakEvent( managerType, sender, e ); + } + + protected virtual bool OnReceiveWeakEvent( Type managerType, object sender, EventArgs e ) + { + if( managerType == typeof( PropertyChangedEventManager ) ) { - this.OnDataGridCollectionView_RootGroupChanged( sender, e ); - return true; + var dataGridCollectionView = this.ItemsSource as DataGridCollectionViewBase; + var eventArgs = e as PropertyChangedEventArgs; + + if( sender == dataGridCollectionView ) + { + this.OnDataGridCollectionView_PropertyChanged( dataGridCollectionView, eventArgs ); + } } else if( managerType == typeof( CollectionChangedEventManager ) ) { - this.OnDataGridDetailDescriptionsChanged( sender, ( NotifyCollectionChangedEventArgs )e ); - return true; + this.OnDataGridDetailDescriptionsChanged( sender as DataGridDetailDescriptionCollection, ( NotifyCollectionChangedEventArgs )e ); } else if( managerType == typeof( ProxyCollectionRefreshEventManager ) ) { - this.OnDataGridCollectionView_ProxyCollectionRefresh( sender, e ); - return true; + this.OnDataGridCollectionView_ProxyCollectionRefresh( sender as DataGridCollectionView, e ); } else if( managerType == typeof( ProxyGroupDescriptionsChangedEventManager ) ) { - this.OnDataGridCollectionView_ProxyGroupDescriptionsChanged( sender, ( NotifyCollectionChangedEventArgs )e ); - return true; + this.OnDataGridCollectionView_ProxyGroupDescriptionsChanged( sender as DataGridCollectionView, ( NotifyCollectionChangedEventArgs )e ); } else if( managerType == typeof( ProxySortDescriptionsChangedEventManager ) ) { - this.OnDataGridCollectionView_ProxySortDescriptionsChanged( sender, ( NotifyCollectionChangedEventArgs )e ); - return true; - } - else if( managerType == typeof( ProxyAutoFilterValuesChangedEventManager ) ) - { - this.OnDataGridCollectionView_ProxyAutoFilterValuesChanged( sender, ( NotifyCollectionChangedEventArgs )e ); - return true; - } - else if( managerType == typeof( ProxyApplyingFilterCriteriasEventManager ) ) - { - this.OnDataGridCollectionView_ProxyApplyingFilterCriterias( sender, e ); - return true; + this.OnDataGridCollectionView_ProxySortDescriptionsChanged( sender as DataGridCollectionView, ( NotifyCollectionChangedEventArgs )e ); } else if( managerType == typeof( ConnectionStateChangedEventManager ) ) { - this.OnDataGridVirtualizingCollectionViewBase_ConnectionStateChanged( sender, e ); - return true; + this.OnDataGridVirtualizingCollectionViewBase_ConnectionStateChanged( sender as DataGridVirtualizingCollectionViewBase, e ); } else if( managerType == typeof( ConnectionErrorChangedEventManager ) ) { - this.OnDataGridVirtualizingCollectionViewBase_ConnectionErrorChanged( sender, e ); - return true; + this.OnDataGridVirtualizingCollectionViewBase_ConnectionErrorChanged( sender as DataGridVirtualizingCollectionViewBase, e ); } else if( managerType == typeof( FrameworkElementUnloadedEventManager ) ) { this.UnhookToUnloaded(); this.SaveDataGridContextState( this.DataGridContext, true, int.MaxValue ); this.CleanUpAfterUnload(); - return true; + } + else + { + return false; } - return false; + return true; } #endregion @@ -6392,30 +6788,23 @@ namespace Xceed.Wpf.DataGrid { get { - return this.CreateDocumentPaginator(); + return null; } } - protected virtual DocumentPaginator CreateDocumentPaginator() - { - return null; - } - #endregion - #region Private Fields - - private IDisposable m_columnsInitDisposable; // = null private IDisposable m_inhibitItemsCollectionChanged; // = null - private int m_beginInitCount; // = 0 - private Cursor m_oldCursor; // = null; private bool? m_oldForceCursor; // = null; private int m_waitCursorCount; // = 0; private FrameworkElement m_itemsHost; // = null - private CustomItemContainerGenerator m_customItemContainerGenerator; // = null + private readonly CustomItemContainerGenerator m_customItemContainerGenerator; // = null + + private AutoScrollManager m_autoScrollManager; + private bool m_startDragSelection; private object m_currentItemInEdition; // = null private RowState m_currentRowInEditionState; // = null @@ -6430,7 +6819,6 @@ namespace Xceed.Wpf.DataGrid private Dictionary m_dataGridContextsStateDictionary; private SelectionManager m_selectionChangerManager; - private HashSet m_dataGridContextToRefreshPeerChlidren; private CommandBinding m_copyCommandBinding; // = null; private CommandBinding m_deleteCommandBinding; // = null; @@ -6442,19 +6830,15 @@ namespace Xceed.Wpf.DataGrid private bool m_isFirstTimeLoaded = true; private WeakReference m_parentWindow; + private WeakReference m_oldColumn = new WeakReference( null ); private BitVector32 m_flags = new BitVector32(); - #endregion - - #region DataGridControlFlags Nested Type - [Flags] private enum DataGridControlFlags { SettingFocusOnCell = 1, IsSetCurrentInProgress = 2, - UsePrintView = 4, IsBoundToDataGridVirtualizingCollectionViewBase = 8, ViewPreservesContainerSize = 16, DebugSaveRestore = 32, @@ -6462,8 +6846,5 @@ namespace Xceed.Wpf.DataGrid SelectedIndexPropertyNeedCoerce = 128, SelectedItemPropertyNeedCoerce = 256 } - - #endregion } - } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridException.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridException.cs index 13017216..592fa340 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridException.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridException.cs @@ -15,8 +15,7 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Text; +using System.Diagnostics; using System.Runtime.Serialization; namespace Xceed.Wpf.DataGrid @@ -66,41 +65,66 @@ namespace Xceed.Wpf.DataGrid #endregion - internal static void ThrowSystemException( string message, Type exceptionType, string source, string argument = "" ) + internal static Exception Create( string message, DataGridControl dataGridControl, string argument = "" ) { Exception exception; - if( exceptionType == typeof( ArgumentException ) ) + var exceptionType = typeof( T ); + + if( typeof( ArgumentException ) == exceptionType ) { exception = new ArgumentException( message, argument ); } - else if( exceptionType == typeof( ArgumentNullException ) ) + else if( typeof( ArgumentNullException ) == exceptionType ) { exception = new ArgumentNullException( message ); } - else if( exceptionType == typeof( ArgumentOutOfRangeException ) ) + else if( typeof( ArgumentOutOfRangeException ) == exceptionType ) { exception = new ArgumentOutOfRangeException( argument, message ); } - else if( exceptionType == typeof( IndexOutOfRangeException ) ) + else if( typeof( IndexOutOfRangeException ) == exceptionType ) { exception = new IndexOutOfRangeException( message ); } - else if( exceptionType == typeof( InvalidOperationException ) ) + else if( typeof( InvalidOperationException ) == exceptionType ) { exception = new InvalidOperationException( message ); } - else if( exceptionType == typeof( NotSupportedException ) ) + else if( typeof( NotSupportedException ) == exceptionType ) { exception = new NotSupportedException( message ); } + else if( typeof( DataGridException ) == exceptionType ) + { + return new DataGridException( message, dataGridControl ); + } + else if( typeof( DataGridInternalException ) == exceptionType ) + { + return new DataGridInternalException( message, dataGridControl ); + } else { exception = new Exception( message ); } - exception.Source = source; - throw exception; + if( dataGridControl != null ) + { + var name = dataGridControl.GridUniqueName; + if( string.IsNullOrEmpty( name ) ) + { + name = dataGridControl.Name; + } + + if( !string.IsNullOrEmpty( name ) ) + { + exception.Source = name; + } + } + + Debug.Assert( exception != null ); + + return exception; } } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridItemContainerManager.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridItemContainerManager.cs index 6d82fae6..a583c7ef 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridItemContainerManager.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridItemContainerManager.cs @@ -23,8 +23,6 @@ namespace Xceed.Wpf.DataGrid { internal sealed class DataGridItemContainerManager { - #region Constructor - internal DataGridItemContainerManager( IDataGridItemContainer owner ) { if( owner == null ) @@ -36,6 +34,22 @@ namespace Xceed.Wpf.DataGrid m_owner = owner; } + #region CanBeRecycled Property + + internal bool CanBeRecycled + { + get + { + if( m_preparedContainers.Any( item => !item.CanBeRecycled ) ) + return false; + + if( m_unpreparedContainers.Any( item => !item.CanBeRecycled ) ) + return false; + + return true; + } + } + #endregion internal void Prepare( DataGridContext dataGridContext, object dataItem ) @@ -47,7 +61,7 @@ namespace Xceed.Wpf.DataGrid this.Update(); } - internal void Clear() + internal void Clear( bool isRecyclingCandidate ) { m_containersPrepared = false; m_dataGridContext = null; @@ -55,7 +69,7 @@ namespace Xceed.Wpf.DataGrid try { - this.ClearContainers(); + this.ClearContainers( isRecyclingCandidate ); } finally { @@ -64,13 +78,24 @@ namespace Xceed.Wpf.DataGrid } } + internal void CleanRecyclingCandidates() + { + var newContainers = m_owner.GetTemplatedChildDataGridItemContainers().ToList(); + + foreach( var container in newContainers ) + { + container.IsRecyclingCandidate = false; + container.CleanRecyclingCandidate(); + } + } + internal void Update() { var newContainers = m_owner.GetTemplatedChildDataGridItemContainers().ToList(); try { - this.ClearContainers( newContainers ); + this.ClearContainers( newContainers, false ); } finally { @@ -107,27 +132,27 @@ namespace Xceed.Wpf.DataGrid fe.ApplyTemplate(); } } - else - { - // When dealing with a row, make sure its cells are properly initialized with their corresponding columns. - row.SynchronizeCellsWithColumns( m_dataGridContext.DataGridControl, null, false ); - } container.PrepareContainer( m_dataGridContext, m_dataItem ); } } - private void ClearContainers() + private void ClearContainers( bool isRecyclingCandidate ) { - this.ClearContainers( new List( 0 ) ); + this.ClearContainers( new List( 0 ), isRecyclingCandidate ); } - private void ClearContainers( ICollection keep ) + private void ClearContainers( ICollection keep, bool isRecyclingCandidate ) { foreach( var container in m_unpreparedContainers.Except( keep ).ToList() ) { m_unpreparedContainers.Remove( container ); + container.IsRecyclingCandidate = isRecyclingCandidate; + + if( isRecyclingCandidate ) + continue; + var row = container as Row; if( row != null ) { @@ -139,12 +164,11 @@ namespace Xceed.Wpf.DataGrid { m_preparedContainers.Remove( container ); + container.IsRecyclingCandidate = isRecyclingCandidate; container.ClearContainer(); } } - #region Private Fields - private readonly IDataGridItemContainer m_owner; private readonly ICollection m_unpreparedContainers = new HashSet(); private readonly ICollection m_preparedContainers = new HashSet(); @@ -152,7 +176,5 @@ namespace Xceed.Wpf.DataGrid private DataGridContext m_dataGridContext; private object m_dataItem; private bool m_containersPrepared; //false - - #endregion } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridItemsHost.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridItemsHost.cs index 1d7ce855..40cd5805 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridItemsHost.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridItemsHost.cs @@ -23,14 +23,13 @@ using System.Windows; using System.Windows.Controls.Primitives; using System.Windows.Input; using System.Windows.Media; +using System.Windows.Threading; using Xceed.Utils.Wpf; namespace Xceed.Wpf.DataGrid { public abstract class DataGridItemsHost : FrameworkElement, ICustomVirtualizingPanel { - #region Constructors - static DataGridItemsHost() { DataGridControl.ParentDataGridControlPropertyKey.OverrideMetadata( @@ -38,8 +37,6 @@ namespace Xceed.Wpf.DataGrid new FrameworkPropertyMetadata( new PropertyChangedCallback( OnParentDataGridControlChanged ) ) ); } - #endregion - #region ParentDataGridControl property protected DataGridControl ParentDataGridControl @@ -85,15 +82,14 @@ namespace Xceed.Wpf.DataGrid m_generator.ItemsChanged += this.HandleGeneratorItemsChanged; m_generator.ContainersRemoved += this.HandleGeneratorContainersRemoved; + m_generator.RecyclingCandidatesCleaned += this.HandleGeneratorRecyclingCandidatesCleaned; m_generatorInitialized = true; } #endregion - #region CachedRootDataGridContext internal property - - private DataGridContext m_cachedRootDataGridContext; + #region CachedRootDataGridContext Internal property internal DataGridContext CachedRootDataGridContext { @@ -110,6 +106,18 @@ namespace Xceed.Wpf.DataGrid } } + private DataGridContext m_cachedRootDataGridContext; + + #endregion + + #region DelayBringIntoView Internal Property + + internal bool DelayBringIntoView + { + get; + private set; + } + #endregion #region Children property @@ -405,25 +413,43 @@ namespace Xceed.Wpf.DataGrid #endregion - #region Protected Methods - protected virtual IList CreateChildCollection() { return new ItemsHostUIElementCollection( this ); } - protected abstract void OnItemsAdded( GeneratorPosition position, int index, int itemCount ); + [Obsolete( "This OnItemsAdded method is obsolete and is no longer called." )] + protected virtual void OnItemsAdded( GeneratorPosition position, int index, int itemCount ) + { + } + + [Obsolete( "This OnItemsRemoved method is obsolete and is no longer called." )] + protected virtual void OnItemsRemoved( GeneratorPosition position, int index, GeneratorPosition oldPosition, int oldIndex, int itemCount, int itemUICount, IList affectedContainers ) + { + } - protected abstract void OnItemsMoved( GeneratorPosition position, int index, GeneratorPosition oldPosition, int oldIndex, int itemCount, int itemUICount, IList affectedContainers ); + [Obsolete( "The OnItemsMoved method is obsolete and is no longer called." )] + protected virtual void OnItemsMoved( GeneratorPosition position, int index, GeneratorPosition oldPosition, int oldIndex, int itemCount, int itemUICount, IList affectedContainers ) + { + } - protected abstract void OnItemsReplaced( GeneratorPosition position, int index, GeneratorPosition oldPosition, int oldIndex, int itemCount, int itemUICount, IList affectedContainers ); + [Obsolete( "The OnItemsReplaced method is obsolete and is no longer called." )] + protected virtual void OnItemsReplaced( GeneratorPosition position, int index, GeneratorPosition oldPosition, int oldIndex, int itemCount, int itemUICount, IList affectedContainers ) + { + } + + protected abstract void OnItemsAdded(); - protected abstract void OnItemsRemoved( GeneratorPosition position, int index, GeneratorPosition oldPosition, int oldIndex, int itemCount, int itemUICount, IList affectedContainers ); + protected abstract void OnItemsRemoved( IList affectedContainers ); protected abstract void OnItemsReset(); protected abstract void OnContainersRemoved( IList removedContainers ); + protected virtual void OnRecyclingCandidatesCleaned( IList recyclingCandidates ) + { + } + protected virtual void OnParentDataGridControlChanged( DataGridControl oldValue, DataGridControl newValue ) { if( ( m_generator != null ) && ( newValue != null ) ) @@ -459,24 +485,7 @@ namespace Xceed.Wpf.DataGrid } } - protected void InvalidateAutomationPeerChildren() - { - DataGridContext dataGridContext = this.CachedRootDataGridContext; - - if( ( dataGridContext == null ) || ( dataGridContext.Peer == null ) ) - return; - - DataGridControl dataGridControl = dataGridContext.DataGridControl; - if( dataGridControl == null ) - return; - - dataGridControl.QueueDataGridContextPeerChlidrenRefresh( dataGridContext ); - } - - #endregion - - #region Internal Methods internal static bool ProcessMoveFocus( Key key ) { @@ -625,7 +634,7 @@ namespace Xceed.Wpf.DataGrid if( ( ownerCell != null ) && ( ownerCell.ParentColumn == this.ParentDataGridControl.CurrentColumn ) ) { - if( object.Equals( ownerCell.ParentRow.DataContext, this.ParentDataGridControl.CurrentItemInEdition ) ) + if( object.Equals( ownerCell.ParentRow.GetEditingDataContext(), this.ParentDataGridControl.CurrentItemInEdition ) ) return true; } } @@ -633,9 +642,21 @@ namespace Xceed.Wpf.DataGrid return false; } - #endregion + internal bool CanRecycleContainer( DependencyObject container ) + { + if( container == null ) + return false; + + var target = container as IDataGridItemContainer; + if( target != null ) + return target.CanBeRecycled; - #region Private Methods + var element = container as UIElement; + if( ( element != null ) && ( element.IsKeyboardFocused || element.IsKeyboardFocusWithin ) ) + return false; + + return true; + } private static void OnParentDataGridControlChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { @@ -656,11 +677,17 @@ namespace Xceed.Wpf.DataGrid // Clean up the previous generator that was used by the ItemsHost m_generator.ItemsChanged -= this.HandleGeneratorItemsChanged; m_generator.ContainersRemoved -= this.HandleGeneratorContainersRemoved; + m_generator.RecyclingCandidatesCleaned -= this.HandleGeneratorRecyclingCandidatesCleaned; } m_generatorInitialized = false; m_cachedRootDataGridContext = null; } + private void HandleGeneratorRecyclingCandidatesCleaned( object sender, RecyclingCandidatesCleanedEventArgs e ) + { + this.OnRecyclingCandidatesCleaned( e.RecyclingCandidates ); + } + private void HandleGeneratorContainersRemoved( object sender, ContainersRemovedEventArgs e ) { this.OnContainersRemoved( e.RemovedContainers ); @@ -668,41 +695,27 @@ namespace Xceed.Wpf.DataGrid private void HandleGeneratorItemsChanged( object sender, CustomGeneratorChangedEventArgs e ) { + // We set this flag to delay any bring into view until a layout pass occured if there is one. + // We don't want the bring into view to occur on a container that may move around during the layout pass. + this.DelayBringIntoView = true; + switch( e.Action ) { case NotifyCollectionChangedAction.Add: - { - this.OnItemsAdded( e.Position, e.Index, e.ItemCount ); - break; - } - case NotifyCollectionChangedAction.Move: - { - this.OnItemsMoved( e.Position, e.Index, e.OldPosition, e.OldIndex, e.ItemCount, e.ItemUICount, e.RemovedContainers ); - break; - } + this.OnItemsAdded(); + break; + case NotifyCollectionChangedAction.Remove: - { - this.OnItemsRemoved( e.Position, e.Index, e.OldPosition, e.OldIndex, e.ItemCount, e.ItemUICount, e.RemovedContainers ); - break; - } - case NotifyCollectionChangedAction.Replace: - { - this.OnItemsReplaced( e.Position, e.Index, e.OldPosition, e.OldIndex, e.ItemCount, e.ItemUICount, e.RemovedContainers ); - break; - } - case NotifyCollectionChangedAction.Reset: - { - this.OnItemsReset(); - break; - } + this.OnItemsRemoved( e.Containers ); + break; + default: - { - throw new System.ComponentModel.InvalidEnumArgumentException( "An unknown action was specified." ); - } + this.OnItemsReset(); + break; } - } - #endregion + this.Dispatcher.BeginInvoke( new Action( () => this.DelayBringIntoView = false ), DispatcherPriority.Loaded ); + } #region ICustomVirtualizingPanel Members diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridVirtualizingPanel.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridVirtualizingPanel.cs index a08beaf4..b579a8fb 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridVirtualizingPanel.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridVirtualizingPanel.cs @@ -14,12 +14,13 @@ ***********************************************************************************/ +using System; +using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; -using System; namespace Xceed.Wpf.DataGrid { @@ -60,6 +61,8 @@ namespace Xceed.Wpf.DataGrid } } + #region ItemCount Property + public int ItemCount { get @@ -91,6 +94,10 @@ namespace Xceed.Wpf.DataGrid } } + #endregion + + #region InternalCustomItemContainerGenerator Property + private CustomItemContainerGenerator InternalCustomItemContainerGenerator { get @@ -103,7 +110,7 @@ namespace Xceed.Wpf.DataGrid CustomItemContainerGenerator retval = null; ItemsControl control1 = ItemsControl.GetItemsOwner( this ); - if((control1 != null) && (control1.IsGrouping == false )) + if( ( control1 != null ) && ( control1.IsGrouping == false ) ) { retval = m_customGenerator; } @@ -112,6 +119,8 @@ namespace Xceed.Wpf.DataGrid } } + #endregion + #region ItemIndex Attached Property public static readonly DependencyProperty ItemIndexProperty = @@ -129,6 +138,59 @@ namespace Xceed.Wpf.DataGrid #endregion ItemIndex Attached Property + protected sealed override void OnItemsChanged( object sender, ItemsChangedEventArgs args ) + { + //I don't want anybody to override this since we might be hooked to the CustomItemContainerGenerator + base.OnItemsChanged( sender, args ); + + //Ok, I only want to process this if i'm NOT hooked to the CustomItemContainerGenerator + if( this.InternalCustomItemContainerGenerator == null ) + { + switch( args.Action ) + { + //In case of a Reset, nothing to do since the Panel base class has cleared the internal children already! + case NotifyCollectionChangedAction.Reset: + break; + + //If there was a removal (collapsing) + //or if there was a Move (edition of a Sorted field) + case NotifyCollectionChangedAction.Move: + case NotifyCollectionChangedAction.Remove: + //remove the concerned range + int index = args.OldPosition.Index; + + Debug.Assert( index != -1 ); + + this.RemoveInternalChildRange( index, args.ItemCount ); + break; + + //if some items were added (expansion) + case NotifyCollectionChangedAction.Add: + //invalidate layout so that the items will be inserted in place! + this.InvalidateMeasure(); + break; + + case NotifyCollectionChangedAction.Replace: + Debug.Fail( "NotifyCollectionChangedAction.Replace" ); + break; + + default: + break; + } + } + } + + protected override void OnClearChildren() + { + //Stop listening to the events of the System Generator if this one is not being used. + if( ( this.InternalCustomItemContainerGenerator == null ) && ( this.ItemContainerGenerator != null ) ) + { + this.ItemContainerGenerator.RemoveAll(); + } + + base.OnClearChildren(); + } + private void InitializeDataGridVirtualizingPanel() { DataGridControl dataGridControl = ItemsControl.GetItemsOwner( this ) as DataGridControl; @@ -143,7 +205,7 @@ namespace Xceed.Wpf.DataGrid { this.RemoveInternalChildRange( 0, this.InternalChildren.Count ); } - ((IItemContainerGenerator)m_customGenerator).RemoveAll(); + ( ( IItemContainerGenerator )m_customGenerator ).RemoveAll(); m_customGenerator.ItemsChanged += OnCustomGeneratorItemsChanged; @@ -158,39 +220,87 @@ namespace Xceed.Wpf.DataGrid { //In case of a Reset, nothing to do since the Panel base class has cleared the internal children already! case NotifyCollectionChangedAction.Reset: - if ( this.InternalChildren.Count > 0 ) - { - this.RemoveInternalChildRange( 0, this.InternalChildren.Count ); - } - else { - this.InvalidateMeasure(); + if( this.InternalChildren.Count > 0 ) + { + this.RemoveInternalChildRange( 0, this.InternalChildren.Count ); + } + else + { + this.InvalidateMeasure(); + } } - break; //If there was a removal (collapsing) //or if there was a Move (edition of a Sorted field) case NotifyCollectionChangedAction.Move: case NotifyCollectionChangedAction.Remove: - //remove the concerned range - int index = e.OldPosition.Index; - if(e.OldPosition.Offset != 0) { - index++; + var containers = new HashSet( e.Containers ?? new DependencyObject[ 0 ] ); + + if( containers.Count > 0 ) + { + var children = this.InternalChildren; + var from = -1; + var removeCount = 0; + var i = 0; + + while( i < children.Count ) + { + var container = children[ i ]; + + if( containers.Contains( container ) ) + { + containers.Remove( container ); + + if( from < 0 ) + { + from = i; + } + + removeCount++; + i++; + } + else if( removeCount > 0 ) + { + Debug.Assert( from >= 0 ); + this.RemoveInternalChildRange( from, removeCount ); + + from = -1; + removeCount = 0; + } + else + { + i++; + } + } + + if( removeCount > 0 ) + { + Debug.Assert( from >= 0 ); + this.RemoveInternalChildRange( from, removeCount ); + } + } + else + { + this.InvalidateMeasure(); + } } - - this.RemoveInternalChildRange( index, e.ItemUICount ); break; //if some items were added (expansion) case NotifyCollectionChangedAction.Add: - //invalidate layout so that the items will be inserted in place! - this.InvalidateMeasure(); + { + //invalidate layout so that the items will be inserted in place! + this.InvalidateMeasure(); + } break; case NotifyCollectionChangedAction.Replace: - Debug.Fail("NotifyCollectionChangedAction.Replace"); + { + Debug.Fail( "NotifyCollectionChangedAction.Replace" ); + } break; default: @@ -198,60 +308,7 @@ namespace Xceed.Wpf.DataGrid } } - protected sealed override void OnItemsChanged( object sender, ItemsChangedEventArgs args ) - { - //I don't want anybody to override this since we might be hooked to the CustomItemContainerGenerator - base.OnItemsChanged( sender, args ); - - //Ok, I only want to process this if i'm NOT hooked to the CustomItemContainerGenerator - if(this.InternalCustomItemContainerGenerator == null) - { - switch( args.Action ) - { - //In case of a Reset, nothing to do since the Panel base class has cleared the internal children already! - case NotifyCollectionChangedAction.Reset: - break; - - //If there was a removal (collapsing) - //or if there was a Move (edition of a Sorted field) - case NotifyCollectionChangedAction.Move: - case NotifyCollectionChangedAction.Remove: - //remove the concerned range - int index = args.OldPosition.Index; - - Debug.Assert( index != -1 ); - - this.RemoveInternalChildRange( index, args.ItemCount ); - break; - - //if some items were added (expansion) - case NotifyCollectionChangedAction.Add: - //invalidate layout so that the items will be inserted in place! - this.InvalidateMeasure(); - break; - - case NotifyCollectionChangedAction.Replace: - Debug.Fail("NotifyCollectionChangedAction.Replace"); - break; - - default: - break; - } - } - } - - protected override void OnClearChildren() - { - //Stop listening to the events of the System Generator if this one is not being used. - if( ( this.InternalCustomItemContainerGenerator == null ) && ( this.ItemContainerGenerator != null ) ) - { - this.ItemContainerGenerator.RemoveAll(); - } - - base.OnClearChildren(); - } - - private static void OnParentDataGridControlChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) + private static void OnParentDataGridControlChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { DataGridVirtualizingPanel panel = ( DataGridVirtualizingPanel )sender; diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemEventDescriptorBase.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemEventDescriptorBase.cs index 39dbed65..00179c25 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemEventDescriptorBase.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemEventDescriptorBase.cs @@ -21,8 +21,6 @@ namespace Xceed.Wpf.DataGrid { internal abstract class DataItemEventDescriptorBase : EventDescriptor { - #region Constructor - protected DataItemEventDescriptorBase( DataItemTypeDescriptor owner, EventDescriptor parent ) : base( parent ) { @@ -32,8 +30,6 @@ namespace Xceed.Wpf.DataGrid m_owner = owner; } - #endregion - #region IsMulticast Property public override bool IsMulticast diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemEventDescriptorFactory.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemEventDescriptorFactory.cs index 0da91534..e5afde0b 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemEventDescriptorFactory.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemEventDescriptorFactory.cs @@ -30,8 +30,6 @@ namespace Xceed.Wpf.DataGrid #endregion - #region Constructor - static DataItemEventDescriptorFactory() { s_reflectEventDescriptorType = Assembly.GetAssembly( typeof( EventDescriptor ) ).GetType( "System.ComponentModel.ReflectEventDescriptor" ); @@ -45,9 +43,7 @@ namespace Xceed.Wpf.DataGrid m_typeDescriptor = typeDescriptor; } - #endregion - - internal DataItemEventDescriptorBase CreateEventDescriptor( EventDescriptor source ) + internal DataItemEventDescriptor CreateEventDescriptor( EventDescriptor source ) { if( !DataItemEventDescriptorFactory.IsReflected( source ) ) return null; @@ -154,10 +150,22 @@ namespace Xceed.Wpf.DataGrid { var d = ( Action )Delegate.CreateDelegate( typeof( Action ), methodInfo, false ); if( d != null ) - return ( source, handler ) => d.Invoke( ( TSource )source, ( THandler )handler ); + return ( source, handler ) => + { + if( !( source is TSource ) ) + return; + + d.Invoke( ( TSource )source, ( THandler )handler ); + }; } - return ( source, handler ) => methodInfo.Invoke( source, new object[] { handler } ); + return ( source, handler ) => + { + if( !( source is TSource ) ) + return; + + methodInfo.Invoke( source, new object[] { handler } ); + }; } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemIndexerDescriptor.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemIndexerDescriptor.cs new file mode 100644 index 00000000..430fab8d --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemIndexerDescriptor.cs @@ -0,0 +1,108 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; + +namespace Xceed.Wpf.DataGrid +{ + internal class DataItemIndexerDescriptor : DataItemPropertyDescriptorBase + { + internal DataItemIndexerDescriptor( DataItemTypeDescriptor owner, IndexerDescriptor parent ) + : base( owner, parent, parent.GetValue, ( !parent.IsReadOnly ) ? parent.SetValue : default( Action ), null ) + { + m_descriptor = parent; + } + + #region ComponentType Property + + public sealed override Type ComponentType + { + get + { + return m_descriptor.ComponentType; + } + } + + #endregion + + #region PropertyType Property + + public sealed override Type PropertyType + { + get + { + return m_descriptor.PropertyType; + } + } + + #endregion + + #region DisplayName Property + + public override string DisplayName + { + get + { + return m_descriptor.DisplayName; + } + } + + #endregion + + #region IndexerParameters Internal Property + + internal string IndexerParameters + { + get + { + return m_descriptor.IndexerParameters; + } + } + + #endregion + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public override bool Equals( object obj ) + { + return ( obj is DataItemIndexerDescriptor ) + && ( base.Equals( obj ) ); + } + + protected override bool MustInhibitValueChanged( object component ) + { + return false; + } + + protected override bool IsValueChangedInhibited( object component ) + { + return false; + } + + protected override void InhibitValueChanged( object component ) + { + } + + protected override void ResetInhibitValueChanged( object component ) + { + } + + private readonly IndexerDescriptor m_descriptor; + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemPropertyDescriptorBase.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemPropertyDescriptorBase.cs index 6f2b2892..0c3c9dfb 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemPropertyDescriptorBase.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemPropertyDescriptorBase.cs @@ -30,8 +30,6 @@ namespace Xceed.Wpf.DataGrid #endregion - #region Constructor - protected DataItemPropertyDescriptorBase( DataItemTypeDescriptor owner, PropertyDescriptor parent, @@ -52,8 +50,6 @@ namespace Xceed.Wpf.DataGrid m_resetter = resetter; } - #endregion - #region IsReadOnly Property public sealed override bool IsReadOnly diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemPropertyDescriptorFactory.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemPropertyDescriptorFactory.cs index 44d13ec0..db7b91b5 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemPropertyDescriptorFactory.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemPropertyDescriptorFactory.cs @@ -48,7 +48,7 @@ namespace Xceed.Wpf.DataGrid #endregion - internal DataItemPropertyDescriptorBase CreatePropertyDescriptor( PropertyDescriptor source ) + internal DataItemPropertyDescriptor CreatePropertyDescriptor( PropertyDescriptor source ) { if( !DataItemPropertyDescriptorFactory.IsReflected( source ) ) return null; @@ -86,6 +86,15 @@ namespace Xceed.Wpf.DataGrid return new DataItemPropertyDescriptor( m_typeDescriptor, source, componentType, propertyType, getter, setter, resetter ); } + internal DataItemIndexerDescriptor CreateIndexerDescriptor( IndexerDescriptor source ) + { + var propertyChangedEvent = this.GetPropertyChangedEvent( null ); + if( propertyChangedEvent != null ) + return new ValueChangeDataItemIndexerDescriptor( m_typeDescriptor, source, propertyChangedEvent ); + + return new DataItemIndexerDescriptor( m_typeDescriptor, source ); + } + private void InitializeEvents() { if( m_eventDescriptors != null ) @@ -111,6 +120,9 @@ namespace Xceed.Wpf.DataGrid { this.InitializeEvents(); + if( string.IsNullOrEmpty( propertyName ) ) + return null; + var eventName = string.Format( CultureInfo.InvariantCulture, "{0}Changed", propertyName ); return ( from ed in m_eventDescriptors.Cast() @@ -240,20 +252,35 @@ namespace Xceed.Wpf.DataGrid var d = ( ValueTypeGetter )Delegate.CreateDelegate( typeof( ValueTypeGetter ), methodInfo, false ); if( d != null ) return ( source ) => - { - var s = ( TSource )source; + { + if( !( source is TSource ) ) + return default( TProperty ); + + var s = ( TSource )source; - return d.Invoke( ref s ); - }; + return d.Invoke( ref s ); + }; } else { var d = ( Func )Delegate.CreateDelegate( typeof( Func ), methodInfo, false ); if( d != null ) - return ( source ) => d.Invoke( ( TSource )source ); + return ( source ) => + { + if( !( source is TSource ) ) + return default( TProperty ); + + return d.Invoke( ( TSource )source ); + }; } - return ( source ) => methodInfo.Invoke( source, null ); + return ( source ) => + { + if( !( source is TSource ) ) + return default( TProperty ); + + return methodInfo.Invoke( source, null ); + }; } public Action CreateSetter( MethodInfo methodInfo ) @@ -267,10 +294,22 @@ namespace Xceed.Wpf.DataGrid { var d = ( Action )Delegate.CreateDelegate( typeof( Action ), methodInfo ); if( d != null ) - return ( source, value ) => d.Invoke( ( TSource )source, ( TProperty )value ); + return ( source, value ) => + { + if( !( source is TSource ) ) + return; + + d.Invoke( ( TSource )source, ( TProperty )value ); + }; } - return ( source, value ) => methodInfo.Invoke( source, new object[] { value } ); + return ( source, value ) => + { + if( !( source is TSource ) ) + return; + + methodInfo.Invoke( source, new object[] { value } ); + }; } public Action CreateResetter( MethodInfo methodInfo ) @@ -283,10 +322,22 @@ namespace Xceed.Wpf.DataGrid { var d = ( Action )Delegate.CreateDelegate( typeof( Action ), methodInfo ); if( d != null ) - return ( source ) => d.Invoke( ( TSource )source ); + return ( source ) => + { + if( !( source is TSource ) ) + return; + + d.Invoke( ( TSource )source ); + }; } - return ( source ) => methodInfo.Invoke( source, null ); + return ( source ) => + { + if( !( source is TSource ) ) + return; + + methodInfo.Invoke( source, null ); + }; } private delegate TProperty ValueTypeGetter( ref TSource source ); diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemTypeDescriptor.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemTypeDescriptor.cs index 1368e829..3937ae65 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemTypeDescriptor.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataItemTypeDescriptor.cs @@ -19,7 +19,9 @@ using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; +using System.Globalization; using System.Linq; +using System.Reflection; namespace Xceed.Wpf.DataGrid { @@ -57,7 +59,7 @@ namespace Xceed.Wpf.DataGrid return sourceEvents; var entry = this.GetEntry(); - var replaceEvents = default( Dictionary ); + var replaceEvents = default( Dictionary ); lock( entry ) { @@ -65,7 +67,7 @@ namespace Xceed.Wpf.DataGrid if( replaceEvents == null ) { - replaceEvents = new Dictionary(); + replaceEvents = new Dictionary(); entry.Events = replaceEvents; var factory = new DataItemEventDescriptorFactory( this ); @@ -90,7 +92,7 @@ namespace Xceed.Wpf.DataGrid { var sourceEvent = sourceEvents[ i ]; - DataItemEventDescriptorBase destinationEvent; + DataItemEventDescriptor destinationEvent; if( replaceEvents.TryGetValue( sourceEvent, out destinationEvent ) ) { destinationEvents[ i ] = destinationEvent; @@ -116,7 +118,7 @@ namespace Xceed.Wpf.DataGrid return sourceProperties; var entry = this.GetEntry(); - var replaceProperties = default( Dictionary ); + var replaceProperties = default( Dictionary ); lock( entry ) { @@ -124,7 +126,7 @@ namespace Xceed.Wpf.DataGrid if( replaceProperties == null ) { - replaceProperties = new Dictionary(); + replaceProperties = new Dictionary(); entry.Properties = replaceProperties; var factory = new DataItemPropertyDescriptorFactory( this ); @@ -149,7 +151,7 @@ namespace Xceed.Wpf.DataGrid { var sourceProperty = sourceProperties[ i ]; - DataItemPropertyDescriptorBase destinationProperty; + DataItemPropertyDescriptor destinationProperty; if( replaceProperties.TryGetValue( sourceProperty, out destinationProperty ) ) { destinationProperties[ i ] = destinationProperty; @@ -163,6 +165,70 @@ namespace Xceed.Wpf.DataGrid return new PropertyDescriptorCollection( destinationProperties ); } + internal DataItemIndexerDescriptor GetIndexer( object[] indexValues ) + { + if( ( indexValues == null ) || ( indexValues.Length <= 0 ) || ( m_targetType == null ) ) + return null; + + var entry = this.GetEntry(); + + lock( entry ) + { + var indexers = entry.Indexers; + var descriptor = default( DataItemIndexerDescriptor ); + var key = new IndexerKey( indexValues ); + + if( ( indexers != null ) && ( indexers.TryGetValue( key, out descriptor ) ) ) + return descriptor; + + var indexer = this.CreateIndexerDescriptor( indexValues ); + if( indexer == null ) + return null; + + var factory = new DataItemPropertyDescriptorFactory( this ); + + descriptor = factory.CreateIndexerDescriptor( indexer ); + if( descriptor == null ) + return null; + + if( indexers == null ) + { + indexers = new Dictionary(); + entry.Indexers = indexers; + } + + indexers.Add( key, descriptor ); + + return descriptor; + } + } + + private IndexerDescriptor CreateIndexerDescriptor( object[] indexValues ) + { + if( ( indexValues == null ) || ( indexValues.Length <= 0 ) || ( m_targetType == null ) ) + return null; + + var best = default( IndexerChoice ); + + foreach( var propertyInfo in m_targetType.GetProperties() ) + { + var candidate = IndexerChoice.GetMatch( propertyInfo, indexValues ); + if( candidate == null ) + continue; + + if( ( best == null ) || ( candidate.CompareTo( best ) > 0 ) ) + { + best = candidate; + } + } + + // No matching indexer was found. + if( best == null ) + return null; + + return IndexerDescriptor.Create( best.Property, indexValues, best.Values ); + } + private Entry GetEntry() { if( m_entry == null ) @@ -203,6 +269,12 @@ namespace Xceed.Wpf.DataGrid } } + private static bool IsNullableType( Type type ) + { + return ( !type.IsValueType ) + || ( type.IsGenericType && ( type.GetGenericTypeDefinition() == typeof( Nullable<> ) ) ); + } + #region Private Fields private readonly Type m_targetType; @@ -236,13 +308,19 @@ namespace Xceed.Wpf.DataGrid private set; } - internal Dictionary Events + internal Dictionary Events + { + get; + set; + } + + internal Dictionary Properties { get; set; } - internal Dictionary Properties + internal Dictionary Indexers { get; set; @@ -250,5 +328,185 @@ namespace Xceed.Wpf.DataGrid } #endregion + + #region IndexerKey Private Class + + private sealed class IndexerKey + { + internal IndexerKey( object[] parameters ) + { + Debug.Assert( ( parameters != null ) && ( parameters.Length > 0 ) ); + + m_parameters = parameters; + } + + public override int GetHashCode() + { + var count = Math.Min( m_parameters.Length, 3 ); + var hashCode = 0; + + for( int i = 0; i < count; i++ ) + { + unchecked + { + hashCode *= 13; + hashCode += m_parameters[ i ].GetHashCode(); + } + } + + return hashCode; + } + + public override bool Equals( object obj ) + { + var target = obj as IndexerKey; + if( target == null ) + return false; + + var targetParameters = target.m_parameters; + if( targetParameters.Length != m_parameters.Length ) + return false; + + for( int i = 0; i < m_parameters.Length; i++ ) + { + if( !object.Equals( targetParameters[ i ], m_parameters[ i ] ) ) + return false; + } + + return true; + } + + private readonly object[] m_parameters; + } + + #endregion + + #region IndexerChoice Private Class + + private sealed class IndexerChoice + { + private IndexerChoice( PropertyInfo propertyInfo, object[] values, FitType[] fitTypes ) + { + m_propertyInfo = propertyInfo; + m_values = values; + m_fitTypes = fitTypes; + } + + internal PropertyInfo Property + { + get + { + return m_propertyInfo; + } + } + + internal object[] Values + { + get + { + return m_values; + } + } + + internal static IndexerChoice GetMatch( PropertyInfo propertyInfo, object[] parameterValues ) + { + if( ( propertyInfo == null ) || ( parameterValues == null ) ) + return null; + + var parameters = propertyInfo.GetIndexParameters(); + if( ( parameters == null ) || ( parameters.Length != parameterValues.Length ) ) + return null; + + var values = new object[ parameters.Length ]; + var fitTypes = new FitType[ parameters.Length ]; + + for( int i = 0; i < parameters.Length; i++ ) + { + var parameterType = parameters[ i ].ParameterType; + var parameterValue = parameterValues[ i ]; + var parameterValueType = ( parameterValue != null ) ? parameterValue.GetType() : typeof( object ); + + if( parameterValue == null ) + { + if( !DataItemTypeDescriptor.IsNullableType( parameterType ) ) + return null; + + fitTypes[ i ] = FitType.KeepAsType; + } + else if( !parameterType.IsAssignableFrom( parameterValueType ) ) + { + var converter = TypeDescriptor.GetConverter( parameterType ); + if( ( converter == null ) || !converter.CanConvertFrom( parameterValueType ) ) + return null; + + try + { + parameterValue = converter.ConvertFrom( null, CultureInfo.InvariantCulture, parameterValue ); + } + catch + { + return null; + } + + // An indexer that takes a parameter of any other type than string is considered a better candidate than + // an indexer that takes a parameter of type string. + fitTypes[ i ] = ( typeof( string ).IsAssignableFrom( parameterType ) ) ? FitType.ConvertToString : FitType.ConvertToType; + } + else + { + if( typeof( string ) == parameterType ) + { + fitTypes[ i ] = FitType.KeepAsString; + } + else if( typeof( object ) == parameterType ) + { + fitTypes[ i ] = FitType.KeepAsObject; + } + else + { + fitTypes[ i ] = FitType.KeepAsType; + } + } + + values[ i ] = parameterValue; + } + + return new IndexerChoice( propertyInfo, values, fitTypes ); + } + + internal int CompareTo( IndexerChoice comparand ) + { + if( comparand == null ) + throw new ArgumentNullException( "comparand" ); + + if( comparand.m_fitTypes.Length != m_fitTypes.Length ) + throw new ArgumentException( "The indexer does not have the same number of parameters.", "comparand" ); + + for( int i = 0; i < m_fitTypes.Length; i++ ) + { + var compare = m_fitTypes[ i ].CompareTo( comparand.m_fitTypes[ i ] ); + if( compare != 0 ) + return compare; + } + + return 0; + } + + private readonly PropertyInfo m_propertyInfo; + private readonly object[] m_values; + private readonly FitType[] m_fitTypes; + + private enum FitType + { + None = 0, + ConvertToString, + KeepAsObject, + KeepAsString, + ConvertToType, + KeepAsType, + } + } + + #endregion } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataRow.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataRow.cs index 7446db0f..122eb7ad 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataRow.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataRow.cs @@ -19,7 +19,7 @@ using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; using System.Windows; -using System.Windows.Data; +using System.Windows.Automation.Peers; using System.Windows.Input; using System.Windows.Media.Animation; using System.Windows.Threading; @@ -29,8 +29,6 @@ namespace Xceed.Wpf.DataGrid { public class DataRow : Row, IEditableObject { - #region CONSTRUCTORS - public DataRow() { this.CommandBindings.Add( new CommandBinding( DataGridCommands.ExpandDetails, @@ -46,15 +44,8 @@ namespace Xceed.Wpf.DataGrid new CanExecuteRoutedEventHandler( OnToggleDetailsCanExecute ) ) ); } - #endregion CONSTRUCTORS - private void OnExpandDetailsExecuted( object sender, ExecutedRoutedEventArgs e ) { - DataGridContext dataGridContext = DataGridControl.GetDataGridContext( this ); - if( ( dataGridContext != null ) && ( this.DataContext != null ) ) - { - dataGridContext.ExpandDetails( this.DataContext ); - } } private void OnExpandDetailsCanExecute( object sender, CanExecuteRoutedEventArgs e ) @@ -73,11 +64,6 @@ namespace Xceed.Wpf.DataGrid private void OnCollapseDetailsExecuted( object sender, ExecutedRoutedEventArgs e ) { - DataGridContext dataGridContext = DataGridControl.GetDataGridContext( this ); - if( ( dataGridContext != null ) && ( this.DataContext != null ) ) - { - dataGridContext.CollapseDetails( this.DataContext ); - } } private void OnCollapseDetailsCanExecute( object sender, CanExecuteRoutedEventArgs e ) @@ -99,7 +85,6 @@ namespace Xceed.Wpf.DataGrid DataGridContext dataGridContext = DataGridControl.GetDataGridContext( this ); if( ( dataGridContext != null ) && ( this.DataContext != null ) ) { - dataGridContext.ToggleDetailExpansion( this.DataContext ); } } @@ -150,6 +135,55 @@ namespace Xceed.Wpf.DataGrid #endregion TitleBarContent Private Property + #region ResortPending property + + private bool ResortPending + { + get + { + return m_flags[ ( int )DataRowFlags.ResortPending ]; + } + set + { + m_flags[ ( int )DataRowFlags.ResortPending ] = value; + } + } + + #endregion + + #region RegroupPending property + + private bool RegroupPending + { + get + { + return m_flags[ ( int )DataRowFlags.RegroupPending ]; + } + set + { + m_flags[ ( int )DataRowFlags.RegroupPending ] = value; + } + } + + #endregion + + #region RepositionPending property + + private bool RepositionPending + { + get + { + return m_flags[ ( int )DataRowFlags.RepositionPending ]; + } + set + { + m_flags[ ( int )DataRowFlags.RepositionPending ] = value; + } + } + + #endregion + + protected override void OnMouseEnter( MouseEventArgs e ) { base.OnMouseEnter( e ); @@ -184,8 +218,7 @@ namespace Xceed.Wpf.DataGrid { DataGridContext dataGridContext = DataGridControl.GetDataGridContext( this ); - // When TableflowViewItemsHost is used and an EmptyDataItem is detected - // We also want to avoid getting an animation when the container is sticky + // When TableflowViewItemsHost is used and an EmptyDataItem is detected. We also want to avoid getting an animation when the container is sticky if( !( item is EmptyDataItem ) && ( dataGridContext != null ) && ( dataGridContext.DataGridControl.GetView() is TableflowView ) @@ -195,19 +228,16 @@ namespace Xceed.Wpf.DataGrid this.ApplyAnimationClock( Row.CellContentOpacityProperty, null ); this.SetValue( Row.CellContentOpacityProperty, 0d ); - // We set the DataContext to an EmptyDataItem to have the - // real data item set later on with an opacity animation. + // We set the DataContext to an EmptyDataItem to have the real data item set later on with an opacity animation. this.DataContext = this.EmptyDataItem; this.UpdateUnboundDataItemContext(); - Debug.Assert( m_affectDataContextOperation == null ); - - // Dispatch a call to SetDataContextDispatched that will update - // the DataContext of the Row and every CreatedCells to the - // DataItem the Row must display. We use a low priority to limit - // the impact on scrolling. - m_affectDataContextOperation = this.Dispatcher.BeginInvoke( - new Action( this.SetDataContextDispatched ), DispatcherPriority.Background, item ); + // Dispatch a call to SetDataContextDispatched that will update the DataContext of the Row and every CreatedCells to the + // DataItem the Row must display. We use a low priority to limit the impact on scrolling. + if( m_affectDataContextOperation == null ) + { + m_affectDataContextOperation = this.Dispatcher.BeginInvoke( new Action( this.SetDataContextDispatched ), DispatcherPriority.Background, item ); + } } else { @@ -221,16 +251,17 @@ namespace Xceed.Wpf.DataGrid protected override void BeginEditCore() { - DataGridContext dataGridContext = DataGridControl.GetDataGridContext( this ); + var dataGridContext = DataGridControl.GetDataGridContext( this ); - DataGridCollectionViewBase dataGridCollectionViewBase = - ( dataGridContext == null ) ? null : dataGridContext.ItemsSourceCollection as DataGridCollectionViewBase; + var dataGridCollectionViewBase = dataGridContext == null ? null : dataGridContext.ItemsSourceCollection as DataGridCollectionViewBase; if( dataGridCollectionViewBase != null ) { // We do not want to call EditItem when the item is the one in the insertionrow if( dataGridCollectionViewBase.CurrentAddItem != this.DataContext ) + { dataGridCollectionViewBase.EditItem( this.DataContext ); + } } else { @@ -238,7 +269,9 @@ namespace Xceed.Wpf.DataGrid // editableObject can be equal to this when the datarow is directly inserted as Item in the DataGridControl. if( ( editableObject != null ) && ( editableObject != this ) ) + { editableObject.BeginEdit(); + } } base.BeginEditCore(); @@ -246,19 +279,20 @@ namespace Xceed.Wpf.DataGrid protected override void EndEditCore() { - DataGridContext dataGridContext = DataGridControl.GetDataGridContext( this ); + var dataGridContext = DataGridControl.GetDataGridContext( this ); base.EndEditCore(); - DataGridCollectionViewBase dataGridCollectionViewBase = - ( dataGridContext == null ) ? null : dataGridContext.ItemsSourceCollection as DataGridCollectionViewBase; + var dataGridCollectionViewBase = dataGridContext == null ? null : dataGridContext.ItemsSourceCollection as DataGridCollectionViewBase; try { if( dataGridCollectionViewBase != null ) { if( dataGridCollectionViewBase.CurrentEditItem == this.DataContext ) + { dataGridCollectionViewBase.CommitEdit(); + } } else { @@ -266,7 +300,9 @@ namespace Xceed.Wpf.DataGrid // editableObject can be equal to this when the datarow is directly inserted as Items in the DataGridControl. if( ( editableObject != null ) && ( editableObject != this ) ) + { editableObject.EndEdit(); + } } } catch( Exception exception ) @@ -283,16 +319,16 @@ namespace Xceed.Wpf.DataGrid // editableObject can be equal to this when the datarow is directly inserted as Items in the DataGridControl. if( ( editableObject != null ) && ( editableObject != this ) ) + { editableObject.BeginEdit(); + } } - // This method will set a validation error on the row and throw back a DataGridValidationException so that - // the row stays in edition. + // This method will set a validation error on the row and throw back a DataGridValidationException so that the row stays in edition. Row.SetRowValidationErrorOnException( this, exception ); } - // Update the created cell's Content from the source in case the IEditableObject EndEdit implementation rectified - // some values. + // Update the created cell's Content from the source in case the IEditableObject EndEdit implementation rectified some values. this.UpdateCellsContentBindingTarget(); } @@ -324,16 +360,17 @@ namespace Xceed.Wpf.DataGrid protected override void CancelEditCore() { - DataGridContext dataGridContext = DataGridControl.GetDataGridContext( this ); + var dataGridContext = DataGridControl.GetDataGridContext( this ); - DataGridCollectionViewBase dataGridCollectionViewBase = - ( dataGridContext == null ) ? null : dataGridContext.ItemsSourceCollection as DataGridCollectionViewBase; + var dataGridCollectionViewBase = dataGridContext == null ? null : dataGridContext.ItemsSourceCollection as DataGridCollectionViewBase; if( dataGridCollectionViewBase != null ) { // We do not want to call EditItem when the item is the one in the insertionrow if( dataGridCollectionViewBase.CurrentEditItem == this.DataContext ) + { dataGridCollectionViewBase.CancelEdit(); + } } else { @@ -341,7 +378,9 @@ namespace Xceed.Wpf.DataGrid // editableObject can be equal to this when the datarow is directly inserted as Items in the DataGridControl. if( ( editableObject != null ) && ( editableObject != this ) ) + { editableObject.CancelEdit(); + } } base.CancelEditCore(); @@ -376,8 +415,7 @@ namespace Xceed.Wpf.DataGrid } // Ensure to stop the opacity animation if it is currently active - if( ( m_opacityAnimationClock != null ) - && ( m_opacityAnimationClock.CurrentState != ClockState.Stopped ) ) + if( ( m_opacityAnimationClock != null ) && ( m_opacityAnimationClock.CurrentState != ClockState.Stopped ) ) { m_opacityAnimationClock.Completed -= this.OpacityAnimationClock_Completed; m_opacityAnimationClock.Controller.Stop(); @@ -393,6 +431,31 @@ namespace Xceed.Wpf.DataGrid } } + protected override void PartialClearContainer() + { + if( m_affectDataContextOperation != null ) + { + m_affectDataContextOperation.Abort(); + m_affectDataContextOperation = null; + } + + // Ensure to stop the opacity animation if it is currently active + if( ( m_opacityAnimationClock != null ) && ( m_opacityAnimationClock.CurrentState != ClockState.Stopped ) ) + { + m_opacityAnimationClock.Completed -= this.OpacityAnimationClock_Completed; + m_opacityAnimationClock.Controller.Stop(); + m_opacityAnimationClock = null; + } + + if( m_storedDataGridContext != null ) + { + ( ( INotifyPropertyChanged )m_storedDataGridContext.Columns ).PropertyChanged -= new PropertyChangedEventHandler( Columns_PropertyChanged ); + m_storedDataGridContext = null; + } + + base.PartialClearContainer(); + } + protected override Cell CreateCell( ColumnBase column ) { if( column == null ) @@ -406,16 +469,6 @@ namespace Xceed.Wpf.DataGrid return ( cell is DataCell ); } - internal static IDisposable DeferCollectionViewRefresh( DataGridContext dataGridContext ) - { - Debug.Assert( dataGridContext != null ); - - if( dataGridContext != null ) - return dataGridContext.Items.DeferRefresh(); - - return null; - } - private void EnsureResort( DataGridContext dataGridContext ) { if( dataGridContext == null ) @@ -527,42 +580,35 @@ namespace Xceed.Wpf.DataGrid [EditorBrowsable( EditorBrowsableState.Never )] protected virtual void SetTitleBarContentBinding( DataGridContext dataGridContext ) { - if( dataGridContext != null ) - { - Xceed.Wpf.DataGrid.Views.ViewBase view = dataGridContext.DataGridControl.GetView(); - - if( ( view is TableView ) || ( view is TableflowView ) ) - return; - - Column headerColumn = dataGridContext.Columns.MainColumn as Column; - - if( headerColumn != null ) - { - BindingBase displayMemberBinding = headerColumn.GetDisplayMemberBinding(); + if( dataGridContext == null ) + return; - if( displayMemberBinding == null ) - { - if( dataGridContext.ItemsSourceFieldDescriptors == null ) - throw new InvalidOperationException( "An attempt was made to create a DisplayMemberBinding before the DataGridContext has been initialized." ); + var view = dataGridContext.DataGridControl.GetView(); + if( ( view is TableView ) || ( view is TableflowView ) ) + return; - string name = headerColumn.FieldName; - ItemsSourceHelper.FieldDescriptor fieldDescriptor; - dataGridContext.ItemsSourceFieldDescriptors.TryGetValue( name, out fieldDescriptor ); + var headerColumn = dataGridContext.Columns.MainColumn as Column; + if( headerColumn == null ) + return; - displayMemberBinding = ItemsSourceHelper.CreateDefaultBinding( this.DataContext is DataRow, name, fieldDescriptor, headerColumn, true, typeof( object ) ); + var displayMemberBinding = headerColumn.GetDisplayMemberBinding(); + if( displayMemberBinding == null ) + { + var dataItem = this.DataContext; + var itemType = ( dataItem != null ) ? dataItem.GetType() : null; - } + displayMemberBinding = ItemsSourceHelper.CreateDefaultBinding( + ItemsSourceHelper.CreateOrGetPropertyDescriptionFromColumn( dataGridContext, headerColumn, itemType ) ); + } - if( displayMemberBinding == null ) - { - Debug.Assert( false, "displayMemberBinding is null." ); - this.ClearValue( DataRow.TitleBarContentProperty ); - } - else - { - this.SetBinding( DataRow.TitleBarContentProperty, displayMemberBinding ); - } - } + if( displayMemberBinding == null ) + { + Debug.Assert( false, "displayMemberBinding is null." ); + this.ClearValue( DataRow.TitleBarContentProperty ); + } + else + { + this.SetBinding( DataRow.TitleBarContentProperty, displayMemberBinding ); } } @@ -608,15 +654,12 @@ namespace Xceed.Wpf.DataGrid { object dataContext = this.DataContext; UnboundDataItem unboundDataItemContext = this.UnboundDataItemContext; - bool isNewContext; foreach( Cell cell in this.CreatedCells ) { - Cell.AssignDataContext( cell, dataContext, unboundDataItemContext, cell.ParentColumn, out isNewContext ); + Cell.AssignDataContext( cell, dataContext, unboundDataItemContext, cell.ParentColumn ); - // We must refresh the Displayed template - // since ShouldDisplayEditor always return - // false when an EmptyDataItem is detected + // We must refresh the Displayed template since ShouldDisplayEditor always return false when an EmptyDataItem is detected cell.RefreshDisplayedTemplate(); } @@ -650,55 +693,11 @@ namespace Xceed.Wpf.DataGrid #endregion - #region PRIVATE PROPERTIES - - private bool ResortPending - { - get - { - return m_flags[ ( int )DataRowFlags.ResortPending ]; - } - set - { - m_flags[ ( int )DataRowFlags.ResortPending ] = value; - } - } - - private bool RegroupPending - { - get - { - return m_flags[ ( int )DataRowFlags.RegroupPending ]; - } - set - { - m_flags[ ( int )DataRowFlags.RegroupPending ] = value; - } - } - - private bool RepositionPending - { - get - { - return m_flags[ ( int )DataRowFlags.RepositionPending ]; - } - set - { - m_flags[ ( int )DataRowFlags.RepositionPending ] = value; - } - } - - #endregion PRIVATE PROPERTIES - - #region PRIVATE FIELDS - private BitVector32 m_flags = new BitVector32(); private DataGridContext m_storedDataGridContext; // = null private DispatcherOperation m_affectDataContextOperation; // = null; - #endregion PRIVATE FIELDS - #region Flags Enum [Flags] diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DefaultCellEditorSelector.xaml b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DefaultCellEditorSelector.xaml index 60d6a1fd..4fe53870 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DefaultCellEditorSelector.xaml +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DefaultCellEditorSelector.xaml @@ -23,293 +23,280 @@ xmlns:conv="clr-namespace:Xceed.Wpf.DataGrid.Converters" xmlns:markup="clr-namespace:Xceed.Wpf.DataGrid.Markup" xmlns:s="clr-namespace:System;assembly=mscorlib"> - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + AutomationProperties.AutomationId="DatePickerEditor" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DefaultCellEditorSelector.xaml.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DefaultCellEditorSelector.xaml.cs index d81c5150..dfe27fa9 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DefaultCellEditorSelector.xaml.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DefaultCellEditorSelector.xaml.cs @@ -15,39 +15,47 @@ ***********************************************************************************/ using System; +using System.Collections; using System.Collections.Generic; -using System.Text; +using System.Diagnostics; using System.Windows; -using System.Collections; +using System.Windows.Threading; namespace Xceed.Wpf.DataGrid { internal partial class DefaultCellEditorSelector : FrameworkElement { - static DefaultCellEditorSelector() - { - Instance = new DefaultCellEditorSelector(); - } + #region Static Fields + + private static DefaultCellEditorSelector s_instance = default( DefaultCellEditorSelector ); + private static readonly List s_instances = new List( 1 ); + + #endregion private DefaultCellEditorSelector() { this.InitializeComponent(); } - private static readonly DefaultCellEditorSelector Instance; + #region ForeignKeyCellEditor Public Static Property - #region TextBoxEditor Public Static Property + public static CellEditor ForeignKeyCellEditor + { + get + { + return DefaultCellEditorSelector.GetCellEditor( "foreignKeyCellEditor" ); + } + } - public static CellEditor TextBoxEditorCache; + #endregion + + #region TextBoxEditor Public Static Property public static CellEditor TextBoxEditor { get { - if( TextBoxEditorCache == null ) - TextBoxEditorCache = DefaultCellEditorSelector.SelectCellEditor( typeof( string ) ); - - return TextBoxEditorCache; + return DefaultCellEditorSelector.SelectCellEditor( typeof( string ) ); } } @@ -55,16 +63,11 @@ namespace Xceed.Wpf.DataGrid #region CheckBoxEditor Public Static Property - public static CellEditor CheckBoxEditorCache; - public static CellEditor CheckBoxEditor { get { - if( CheckBoxEditorCache == null ) - CheckBoxEditorCache = DefaultCellEditorSelector.SelectCellEditor( typeof( bool ) ); - - return CheckBoxEditorCache; + return DefaultCellEditorSelector.SelectCellEditor( typeof( bool ) ); } } @@ -72,122 +75,155 @@ namespace Xceed.Wpf.DataGrid #region DateTimeEditor Public Static Editor - public static CellEditor DateTimeEditorCache; - public static CellEditor DateTimeEditor { get { - if( DateTimeEditorCache == null ) - DateTimeEditorCache = DefaultCellEditorSelector.SelectCellEditor( typeof( DateTime ) ); - - return DateTimeEditorCache; + return DefaultCellEditorSelector.SelectCellEditor( typeof( DateTime ) ); } } #endregion - #region ForeignKeyCellEditor Public Static Property + public static CellEditor SelectCellEditor( Type dataType ) + { + if( dataType == null ) + return null; - private static CellEditor ForeignKeyEditorCache; + if( dataType.IsGenericType && ( dataType.GetGenericTypeDefinition() == typeof( Nullable<> ) ) ) + { + dataType = Nullable.GetUnderlyingType( dataType ); + } - public static CellEditor ForeignKeyCellEditor + var editor = default( CellEditor ); + if( DefaultCellEditorSelector.TryGetCellEditor( dataType.FullName, out editor ) ) + return editor; + + return null; + } + + private static DataTemplate GetDataTemplate( object key ) { - get - { - if( ForeignKeyEditorCache == null ) - { - ForeignKeyEditorCache = DefaultCellEditorSelector.ThreadSafeFindResource( "foreignKeyCellEditor" ) as CellEditor; - ForeignKeyEditorCache.EditTemplate.Seal(); - } + var resource = default( DataTemplate ); + if( !DefaultCellEditorSelector.TryGetDataTemplate( key, out resource ) ) + throw new KeyNotFoundException( "Resource not found" ); - return ForeignKeyEditorCache; - } + return resource; } - #endregion + private static bool TryGetDataTemplate( object key, out DataTemplate value ) + { + var resource = default( object ); + if( !DefaultCellEditorSelector.TryGetResource( key, out resource ) ) + { + value = default( DataTemplate ); + return false; + } + else + { + value = DefaultCellEditorSelector.TrySeal( resource as DataTemplate ); + return ( value != null ); + } + } - #region LinqCellEditor Public Static Editor + private static CellEditor GetCellEditor( object key ) + { + var resource = default( CellEditor ); + if( !DefaultCellEditorSelector.TryGetCellEditor( key, out resource ) ) + throw new KeyNotFoundException( "Resource not found" ); - private static CellEditor LinqCellEditorCache; + return resource; + } - public static CellEditor LinqCellEditor + private static bool TryGetCellEditor( object key, out CellEditor value ) { - get + var resource = default( object ); + if( !DefaultCellEditorSelector.TryGetResource( key, out resource ) ) { - if( LinqCellEditorCache == null ) - { - LinqCellEditorCache = DefaultCellEditorSelector.ThreadSafeFindResource( "linqCellEditor" ) as CellEditor; - LinqCellEditorCache.EditTemplate.Seal(); - } - - return LinqCellEditorCache; + value = default( CellEditor ); + return false; + } + else + { + value = DefaultCellEditorSelector.TryFreeze( resource as CellEditor ); + return ( value != null ); } } - #endregion - - public static CellEditor SelectCellEditor( Type dataType ) + private static bool TryGetResource( object key, out object value ) { - CellEditor cellEditor = null; + value = null; + + var dispatcher = Dispatcher.CurrentDispatcher; + if( dispatcher == null ) + return false; + + var target = default( DefaultCellEditorSelector ); - if( dataType != null ) + lock( ( ( ICollection )s_instances ).SyncRoot ) { - if( ( dataType.IsGenericType ) && ( dataType.GetGenericTypeDefinition() == typeof( Nullable<> ) ) ) - dataType = Nullable.GetUnderlyingType( dataType ); + for( int i = s_instances.Count - 1; i >= 0; i-- ) + { + var instance = s_instances[ i ].Target as DefaultCellEditorSelector; + + if( instance == null ) + { + s_instances.RemoveAt( i ); + } + else if( instance.Dispatcher == dispatcher ) + { + target = instance; + + // We could exit the loop but we don't because we want to clean up the list + // and keep it small. We don't want it to become large with lots of empty + // WeakReference. + //break; + } + } - cellEditor = DefaultCellEditorSelector.ThreadSafeTryFindResource( dataType.FullName ) as CellEditor; + if( target == null ) + { + target = new DefaultCellEditorSelector(); + s_instances.Add( new WeakReference( target ) ); + } - if( cellEditor != null ) - DefaultCellEditorSelector.ThreadSafeTryFreezeEditor( cellEditor ); + // We keep a strong reference on the target instance to prevent that instance + // from being garbage collected. We assume that we will need that instance + // again for other calls. We don't want to have to create a new instance to + // query for a single resource. + s_instance = target; } - return cellEditor; - } - - private static object ThreadSafeTryFindResource( string key ) - { - Func func = ( resourceKey => DefaultCellEditorSelector.Instance.TryFindResource( resourceKey ) ); + Debug.Assert( target != null ); - if( DefaultCellEditorSelector.Instance.CheckAccess() ) - return func( key ); + value = target.TryFindResource( key ); - return DefaultCellEditorSelector.Instance.Dispatcher.Invoke( func, key ); + return ( value != null ); } - private static object ThreadSafeFindResource( string key ) + private static DataTemplate TrySeal( DataTemplate template ) { - Func func = ( resourceKey => DefaultCellEditorSelector.Instance.FindResource( resourceKey ) ); - - if( DefaultCellEditorSelector.Instance.CheckAccess() ) - return func( key ); + if( ( template != null ) && !template.IsSealed ) + { + template.Seal(); + } - return DefaultCellEditorSelector.Instance.Dispatcher.Invoke( func, key ); + return template; } - private static void ThreadSafeTryFreezeEditor( CellEditor cellEditor ) + private static CellEditor TryFreeze( CellEditor editor ) { - if( cellEditor == null ) - throw new ArgumentNullException( "cellEditor" ); - - if( DefaultCellEditorSelector.Instance.CheckAccess() ) + if( ( editor != null ) && !editor.IsFrozen ) { - if( cellEditor.IsFrozen ) - return; - - if( ( cellEditor.EditTemplate != null ) && ( !cellEditor.EditTemplate.IsSealed ) ) - cellEditor.EditTemplate.Seal(); - - System.Diagnostics.Debug.Assert( cellEditor.CanFreeze ); + DefaultCellEditorSelector.TrySeal( editor.EditTemplate ); - if( cellEditor.CanFreeze ) - cellEditor.Freeze(); - } - else - { - DefaultCellEditorSelector.Instance.Dispatcher.Invoke( - new Action( DefaultCellEditorSelector.ThreadSafeTryFreezeEditor ), cellEditor ); + if( editor.CanFreeze ) + { + editor.Freeze(); + } } + + return editor; } } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DefaultDetailConfiguration.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DefaultDetailConfiguration.cs index 3b752375..7701f8f0 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DefaultDetailConfiguration.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DefaultDetailConfiguration.cs @@ -275,8 +275,6 @@ namespace Xceed.Wpf.DataGrid return; m_defaultHeadersFootersAdded = true; - - DetailConfiguration.AddDefaultHeadersFooters( this.Headers, false ); } private bool m_defaultHeadersFootersAdded = false; diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DetailConfiguration.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DetailConfiguration.cs index 0d73e4da..86423d25 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DetailConfiguration.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DetailConfiguration.cs @@ -21,17 +21,26 @@ using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; +using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; using Xceed.Wpf.DataGrid.Markup; +using Xceed.Wpf.DataGrid.Utils; using Xceed.Wpf.DataGrid.Views; namespace Xceed.Wpf.DataGrid { internal sealed class DetailConfiguration : DependencyObject, IWeakEventListener, ISupportInitialize, INotifyPropertyChanged { + #region Static Fields + + internal static readonly string DataGridControlPropertyName = PropertyHelper.GetPropertyName( ( DetailConfiguration d ) => d.DataGridControl ); + internal static readonly string DetailDescriptionPropertyName = PropertyHelper.GetPropertyName( ( DetailConfiguration d ) => d.DetailDescription ); + + #endregion + static DetailConfiguration() { DetailConfiguration.DetailConfigurationsProperty = DetailConfiguration.DetailConfigurationsPropertyKey.DependencyProperty; @@ -46,24 +55,26 @@ namespace Xceed.Wpf.DataGrid public DetailConfiguration() { - var columns = new ColumnCollection( this.DataGridControl, this ); + var columns = new ColumnCollection( null, this ); - this.SetColumns( columns ); - this.Columns.CollectionChanged += new NotifyCollectionChangedEventHandler( this.OnColumnsCollectionChanged ); - VisibilityChangedEventManager.AddListener( this.Columns, this ); + m_columnManager = new ColumnHierarchyManager( columns ); - this.SetVisibleColumns( new ReadOnlyColumnCollection() ); + this.SetColumns( columns ); + this.SetVisibleColumns( m_columnManager.VisibleColumns ); - m_columnsByVisiblePosition = new HashedLinkedList(); m_columnSynchronizationManager = new ColumnSynchronizationManager( this ); + m_columnManagerRowConfiguration = new ColumnManagerRowConfiguration(); this.SetHeaders( new ObservableCollection() ); this.SetFooters( new ObservableCollection() ); this.SetGroupLevelDescriptions( new GroupLevelDescriptionCollection() ); - this.SetDetailConfigurations( new DetailConfigurationCollection( this.DataGridControl, this ) ); + this.SetDetailConfigurations( new DetailConfigurationCollection( null, this ) ); + + columns.CollectionChanged += new NotifyCollectionChangedEventHandler( this.OnColumnsCollectionChanged ); CollectionChangedEventManager.AddListener( this.DetailConfigurations, this ); + this.BeginInit(); } private static void BuildDefaultTemplates() @@ -141,7 +152,7 @@ namespace Xceed.Wpf.DataGrid private static DataTemplate DefaultColumnManagerRowTemplate; private static DataTemplate DefaultGroupByControlTemplate; - internal static void AddDefaultHeadersFooters( ObservableCollection headersCollection, bool areDetailsFlatten ) + internal static void AddDefaultHeadersFooters( ObservableCollection headersCollection, int mergedHeadersCount, bool areDetailsFlatten ) { if( !areDetailsFlatten ) { @@ -150,57 +161,6 @@ namespace Xceed.Wpf.DataGrid } } - internal static void SynchronizeDetailConfigurations( - DataGridDetailDescriptionCollection dataGridDetailDescriptionCollection, - DetailConfigurationCollection detailConfigurationCollection, - bool autoCreateDetailConfigurations, - bool autoCreateForeignKeyConfigurations, - bool autoRemoveUnassociated ) - { - HashSet detailConfigWithAssociation = new HashSet(); - - foreach( DataGridDetailDescription detailDescription in dataGridDetailDescriptionCollection ) - { - DetailConfiguration detailConfig = detailConfigurationCollection[ detailDescription.RelationName ]; - - if( detailConfig == null ) - { - if( autoCreateDetailConfigurations ) - { - detailConfig = new DetailConfiguration(); - - detailConfig.SetIsAutoCreated( true ); - detailConfig.RelationName = detailDescription.RelationName; - detailConfig.AutoCreateForeignKeyConfigurations = autoCreateForeignKeyConfigurations; - detailConfig.AutoRemoveColumnsAndDetailConfigurations = autoRemoveUnassociated; - detailConfigurationCollection.Add( detailConfig ); - } - } - - if( detailConfig != null ) - { - detailConfigWithAssociation.Add( detailConfig ); - detailConfig.SynchronizeWithDetailDescription( detailDescription ); - } - } - - for( int i = detailConfigurationCollection.Count - 1; i >= 0; i-- ) - { - DetailConfiguration detailConfig = detailConfigurationCollection[ i ]; - - if( !detailConfigWithAssociation.Contains( detailConfig ) ) - { - detailConfig.DetachFromDetailDescription(); - - if( ( autoRemoveUnassociated ) && ( detailConfig.IsAutoCreated ) ) - { - DetailConfiguration.CleanupDetailConfigurations( detailConfig.DetailConfigurations, autoRemoveUnassociated ); - detailConfigurationCollection.RemoveAt( i ); - } - } - } - } - internal static void SynchronizeAddedConfigurations( IList addedDetailConfigs, DataGridDetailDescriptionCollection detailDescriptions ) { foreach( DetailConfiguration detailConfig in addedDetailConfigs ) @@ -300,44 +260,6 @@ namespace Xceed.Wpf.DataGrid #endregion AutoCreateColumns Property - #region AutoCreateDetailConfigurations Property - - public static readonly DependencyProperty AutoCreateDetailConfigurationsProperty = - DataGridControl.AutoCreateDetailConfigurationsProperty.AddOwner( typeof( DetailConfiguration ), new FrameworkPropertyMetadata( true ) ); - - public bool AutoCreateDetailConfigurations - { - get - { - return ( bool )this.GetValue( DetailConfiguration.AutoCreateDetailConfigurationsProperty ); - } - set - { - this.SetValue( DetailConfiguration.AutoCreateDetailConfigurationsProperty, value ); - } - } - - #endregion AutoCreateColumns Property - - #region AutoRemoveColumnsAndDetailConfigurations Property - - public static readonly DependencyProperty AutoRemoveColumnsAndDetailConfigurationsProperty = - DataGridControl.AutoRemoveColumnsAndDetailConfigurationsProperty.AddOwner( typeof( DetailConfiguration ) ); - - public bool AutoRemoveColumnsAndDetailConfigurations - { - get - { - return ( bool )this.GetValue( DataGridControl.AutoRemoveColumnsAndDetailConfigurationsProperty ); - } - set - { - this.SetValue( DataGridControl.AutoRemoveColumnsAndDetailConfigurationsProperty, value ); - } - } - - #endregion AutoRemoveColumnsAndDetailConfigurations Property - #region Columns Read-Only Property internal static readonly DependencyPropertyKey ColumnsPropertyKey = @@ -776,6 +698,16 @@ namespace Xceed.Wpf.DataGrid #endregion + #region ForeignKeysUpdatedOnAutoCreate Property + + internal bool ForeignKeysUpdatedOnAutoCreate + { + get; + set; + } + + #endregion + #region CurrentColumn Property internal ColumnBase CurrentColumn @@ -808,29 +740,23 @@ namespace Xceed.Wpf.DataGrid { get { - return m_columnsByVisiblePosition; + return m_columnManager.ColumnsByVisiblePosition; } } - private HashedLinkedList m_columnsByVisiblePosition; - #endregion - #region ItemsSourceFieldDescriptors Property + #region ItemsSourcePropertyDescriptions Internal Property - internal Dictionary ItemsSourceFieldDescriptors + internal PropertyDescriptionRouteDictionary ItemsSourcePropertyDescriptions { get { - return m_itemsSourceFieldDescriptors; - } - set - { - m_itemsSourceFieldDescriptors = value; + return m_itemsSourcePropertyDescriptions; } } - private Dictionary m_itemsSourceFieldDescriptors; // = null + private readonly PropertyDescriptionRouteDictionary m_itemsSourcePropertyDescriptions = new PropertyDescriptionRouteDictionary(); #endregion @@ -907,30 +833,87 @@ namespace Xceed.Wpf.DataGrid { get { - var collection = this.ContainingCollection; - if( collection != null ) - return collection.DataGridControl; - - return null; + return m_dataGridControl; } private set { - if( this.Columns != null ) + if( value == m_dataGridControl ) + return; + + var oldDataGridControl = m_dataGridControl; + + if( m_dataGridControl != null ) + { + ViewChangedEventManager.RemoveListener( m_dataGridControl, this ); + } + + m_dataGridControl = value; + + if( m_dataGridControl != null ) { - this.Columns.DataGridControl = value; + ViewChangedEventManager.AddListener( m_dataGridControl, this ); } - if( this.DetailConfigurations != null ) + if( value != null ) { - this.DetailConfigurations.DataGridControl = value; + m_columnManager.Initialize( value ); + m_columnManager.SetFixedColumnCount( TableView.GetFixedColumnCount( this ) ); + } + else + { + m_columnManager.Clear(); } - m_fieldNameMap.SetSource( value, this.DetailDescription ); + var detailConfigurations = this.DetailConfigurations; + if( detailConfigurations != null ) + { + detailConfigurations.DataGridControl = value; + } + + this.InitializeItemPropertyMap( this.DataGridControl, this.DetailDescription ); + this.OnPropertyChanged( DetailConfiguration.DataGridControlPropertyName ); - this.OnPropertyChanged( "DataGridControl" ); + if( m_dataGridControl == null ) + { + this.BeginInit(); + } + else if( oldDataGridControl == null ) + { + this.EndInit(); + } } } + private DataGridControl m_dataGridControl; + + #endregion + + #region DataGridContext Property + + internal DataGridContext DataGridContext + { + get + { + return m_dataGridContexts.FirstOrDefault(); + } + } + + internal void AddDataGridContext( DataGridContext dataGridContext ) + { + Debug.Assert( dataGridContext != null ); + + m_dataGridContexts.Add( dataGridContext ); + } + + internal void RemoveDataGridContext( DataGridContext dataGridContext ) + { + var oldCount = m_dataGridContexts.Count; + m_dataGridContexts.Remove( dataGridContext ); + var newCount = m_dataGridContexts.Count; + } + + private readonly ICollection m_dataGridContexts = new HashSet(); + #endregion #region ParentDetailConfiguration Internal Property @@ -948,58 +931,59 @@ namespace Xceed.Wpf.DataGrid #endregion - #region IsAutoCreated Internal Property + #region ColumnManagerRowConfiguration Internal Property - internal bool IsAutoCreated + internal ColumnManagerRowConfiguration ColumnManagerRowConfiguration { get { - return m_isAutoCreated; + return m_columnManagerRowConfiguration; } } - internal void SetIsAutoCreated( bool newValue ) - { - m_isAutoCreated = newValue; - } - - private bool m_isAutoCreated = false; + private readonly ColumnManagerRowConfiguration m_columnManagerRowConfiguration; #endregion - #region IsAttachedToDetailDescription Internal Read-Only Property + #region IsAutoCreated Internal Property - internal bool IsAttachedToDetailDescription + internal bool IsAutoCreated { get { - return m_isAttachedToDetailDescription; + return m_isAutoCreated; } private set { - if( value == m_isAttachedToDetailDescription ) - return; - - m_isAttachedToDetailDescription = value; - this.OnPropertyChanged( "IsAttachedToDetailDescription" ); + m_isAutoCreated = value; } } - private bool m_isAttachedToDetailDescription; //false + private bool m_isAutoCreated = false; + + #endregion + + #region IsCreatedFromSelector Property + + private bool IsCreatedFromSelector + { + get; + set; + } #endregion #region ItemPropertyMap Internal Property - internal FieldNameMap ItemPropertyMap + internal DataGridItemPropertyMap ItemPropertyMap { get { - return m_fieldNameMap; + return m_itemPropertyMap; } } - private readonly FieldNameMapProxy m_fieldNameMap = new FieldNameMapProxy(); + private readonly DataGridItemPropertyMap m_itemPropertyMap = new DataGridItemPropertyMap(); #endregion @@ -1045,18 +1029,6 @@ namespace Xceed.Wpf.DataGrid #endregion - #region RecyclingManager Internal Read-Only property - - internal RecyclingManager RecyclingManager - { - get - { - return m_recyclingManager; - } - } - - #endregion - #region IsDeleteCommandEnabled Property public static readonly DependencyProperty IsDeleteCommandEnabledProperty = DependencyProperty.Register( @@ -1084,23 +1056,21 @@ namespace Xceed.Wpf.DataGrid #endregion IsDeleteCommandEnabled Property - #region DetailDescription Private Property + #region DetailDescription Internal Property - private DataGridDetailDescription DetailDescription + internal DataGridDetailDescription DetailDescription { get { return m_detailDescription; } - set + private set { if( value == m_detailDescription ) return; m_detailDescription = value; - this.OnPropertyChanged( "DetailDescription" ); - - this.IsAttachedToDetailDescription = ( value != null ); + this.OnPropertyChanged( DetailConfiguration.DetailDescriptionPropertyName ); } } @@ -1121,6 +1091,9 @@ namespace Xceed.Wpf.DataGrid if( value == m_containingCollection ) return; + if( ( m_containingCollection != null ) && ( value != null ) ) + throw new InvalidOperationException( "The DetailConfiguration is already contained in another DetailConfigurationCollection." ); + if( m_containingCollection != null ) { ( ( INotifyPropertyChanged )m_containingCollection ).PropertyChanged -= new PropertyChangedEventHandler( this.OnContainingCollectionPropertyChanged ); @@ -1173,22 +1146,39 @@ namespace Xceed.Wpf.DataGrid #endregion - #region IsSettingFixedColumnCount Property + #region ColumnManager Internal Property - internal bool IsSettingFixedColumnCount + internal ColumnHierarchyManager ColumnManager { - get; - set; + get + { + return m_columnManager; + } } + private readonly ColumnHierarchyManager m_columnManager; + #endregion - #region Events + public IDisposable DeferColumnsUpdate() + { + return ColumnHierarchyManagerHelper.DeferColumnsUpdate( this ); + } - internal event EventHandler RequestingDelayBringIntoViewAndFocusCurrent; - internal event EventHandler FixedColumnCountChanged; + public bool MoveColumnBefore( ColumnBase current, ColumnBase next ) + { + return ColumnHierarchyManagerHelper.MoveColumnBefore( this, current, next ); + } - #endregion + public bool MoveColumnAfter( ColumnBase current, ColumnBase previous ) + { + return ColumnHierarchyManagerHelper.MoveColumnAfter( this, current, previous ); + } + + public bool MoveColumnUnder( ColumnBase current, ColumnBase parent ) + { + return ColumnHierarchyManagerHelper.MoveColumnUnder( this, current, parent ); + } protected override void OnPropertyChanged( DependencyPropertyChangedEventArgs e ) { @@ -1196,11 +1186,14 @@ namespace Xceed.Wpf.DataGrid if( e.Property == DetailConfiguration.GroupConfigurationSelectorProperty ) { - if( this.GroupConfigurationSelectorChanged != null ) + var handler = this.GroupConfigurationSelectorChanged; + if( handler != null ) { - this.GroupConfigurationSelectorChanged( this, EventArgs.Empty ); + handler.Invoke( this, EventArgs.Empty ); } } + + this.OnPropertyChanged( e.Property.Name ); } internal void AddDefaultHeadersFooters() @@ -1210,7 +1203,7 @@ namespace Xceed.Wpf.DataGrid m_defaultHeadersFootersAdded = true; - DetailConfiguration.AddDefaultHeadersFooters( this.Headers, this.DataGridControl.AreDetailsFlatten ); + DetailConfiguration.AddDefaultHeadersFooters( this.Headers, 0, this.DataGridControl.AreDetailsFlatten ); } internal void SynchronizeForeignKeyConfigurations() @@ -1220,7 +1213,7 @@ namespace Xceed.Wpf.DataGrid return; ForeignKeyConfiguration.UpdateColumnsForeignKeyConfigurationsFromDataGridCollectionView( - this.Columns.FieldNameToColumnDictionary, + this.Columns, detailDescription.ItemProperties, this.AutoCreateForeignKeyConfigurations ); } @@ -1238,103 +1231,91 @@ namespace Xceed.Wpf.DataGrid this.ContainingCollection = null; } - internal void RaiseFixedColumnCountChanged( FixedColumnCountInfoEventArgs infoEventArgs ) + private void SynchronizeWithDetailDescription( DataGridDetailDescription detailDescription ) { - this.IsSettingFixedColumnCount = true; + if( detailDescription == this.DetailDescription ) + return; - if( this.FixedColumnCountChanged != null ) - { - this.FixedColumnCountChanged( this, infoEventArgs ); - } - } + this.DetachFromDetailDescription( false ); - private void SynchronizeWithDetailDescription( DataGridDetailDescription detailDescription ) - { - if( detailDescription != this.DetailDescription ) - { - this.DetachFromDetailDescription(); + m_shouldCreateColumns = true; + this.DetailDescription = detailDescription; - m_shouldCreateColumns = true; - this.DetailDescription = detailDescription; + DataGridSortDescriptionCollection dataGridSortDescriptionCollection; + ObservableCollection groupDescriptionCollection; - DataGridSortDescriptionCollection dataGridSortDescriptionCollection; - ObservableCollection groupDescriptionCollection; + if( detailDescription != null ) + { + groupDescriptionCollection = detailDescription.GroupDescriptions; - if( detailDescription != null ) - { - groupDescriptionCollection = detailDescription.GroupDescriptions; + //register to the collectionchanged of the DataGridDetailDescription collection of the detailDescription matching this one. + dataGridSortDescriptionCollection = detailDescription.DataGridSortDescriptions; - //register to the collectionchanged of the DataGridDetailDescription collection of the detailDescription matching this one. - dataGridSortDescriptionCollection = detailDescription.DataGridSortDescriptions; + this.RegisterItemProperties( detailDescription.ItemProperties ); - CollectionChangedEventManager.AddListener( detailDescription.ItemProperties, this ); - CollectionChangedEventManager.AddListener( detailDescription.DetailDescriptions, this ); - } - else - { - groupDescriptionCollection = new GroupDescriptionCollection(); - dataGridSortDescriptionCollection = new DataGridSortDescriptionCollection(); - } + CollectionChangedEventManager.AddListener( detailDescription.DetailDescriptions, this ); + } + else + { + groupDescriptionCollection = new GroupDescriptionCollection(); + dataGridSortDescriptionCollection = new DataGridSortDescriptionCollection(); + } - m_groupDescriptions = groupDescriptionCollection; - m_sortDescriptions = dataGridSortDescriptionCollection; - m_sortDescriptionsSyncContext = null; //clear it, if it was ever set! - m_fieldNameMap.SetSource( this.DataGridControl, detailDescription ); + m_groupDescriptions = groupDescriptionCollection; + m_sortDescriptions = dataGridSortDescriptionCollection; + m_sortDescriptionsSyncContext = null; //clear it, if it was ever set! - //This update is required since there might be some columns in the Columns collection after the XAML parsing of the DetailConfiguration - this.UpdateColumnSortOrder(); + this.InitializeItemPropertyMap( this.DataGridControl, detailDescription ); - //This update is required since we want the GroupLevelDescriptions to be created if DetailConfiguration in XAML - //contains GroupDescriptions - DataGridContext.UpdateGroupLevelDescriptions( this.GroupLevelDescriptions, new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Reset ), this.GroupDescriptions, this.Columns ); + //This update is required since there might be some columns in the columns collection after the XAML parsing of the DetailConfiguration + this.UpdateColumnSortOrder(); - CollectionChangedEventManager.AddListener( m_sortDescriptions, this ); - CollectionChangedEventManager.AddListener( m_groupDescriptions, this ); + //This update is required since we want the GroupLevelDescriptions to be created if DetailConfiguration in XAML + //contains GroupDescriptions + DataGridContext.UpdateGroupLevelDescriptions( this.GroupLevelDescriptions, + new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Reset ), + this.GroupDescriptions, + this.Columns ); - if( detailDescription != null ) + CollectionChangedEventManager.AddListener( m_sortDescriptions, this ); + CollectionChangedEventManager.AddListener( m_groupDescriptions, this ); + + if( detailDescription != null ) + { + if( this.ReadLocalValue( DetailConfiguration.TitleProperty ) == DependencyProperty.UnsetValue ) { - if( this.ReadLocalValue( DetailConfiguration.TitleProperty ) == DependencyProperty.UnsetValue ) + if( detailDescription.Title == null ) { - if( detailDescription.Title == null ) - { - this.Title = detailDescription.RelationName; - } - else - { - this.Title = detailDescription.Title; - } + this.Title = detailDescription.RelationName; } - - if( ( this.ReadLocalValue( DetailConfiguration.TitleTemplateProperty ) == DependencyProperty.UnsetValue ) - && ( detailDescription.TitleTemplate != null ) ) + else { - this.TitleTemplate = detailDescription.TitleTemplate; + this.Title = detailDescription.Title; } + } - DetailConfiguration.SynchronizeDetailConfigurations( - detailDescription.DetailDescriptions, - this.DetailConfigurations, - this.AutoCreateDetailConfigurations, - this.AutoCreateForeignKeyConfigurations, - this.AutoRemoveColumnsAndDetailConfigurations ); + if( ( this.ReadLocalValue( DetailConfiguration.TitleTemplateProperty ) == DependencyProperty.UnsetValue ) + && ( detailDescription.TitleTemplate != null ) ) + { + this.TitleTemplate = detailDescription.TitleTemplate; } } - if( detailDescription != null ) - { - ForeignKeyConfiguration.UpdateColumnsForeignKeyConfigurationsFromDataGridCollectionView( - this.Columns.FieldNameToColumnDictionary, - detailDescription.ItemProperties, - this.AutoCreateForeignKeyConfigurations ); - } + this.UpdateColumns(); } private void DetachFromDetailDescription() + { + this.DetachFromDetailDescription( true ); + } + + private void DetachFromDetailDescription( bool synchronizeColumns ) { var detailDescription = this.DetailDescription; if( detailDescription != null ) { - CollectionChangedEventManager.RemoveListener( detailDescription.ItemProperties, this ); + this.UnregisterItemProperties( detailDescription.ItemProperties ); + CollectionChangedEventManager.RemoveListener( detailDescription.DetailDescriptions, this ); } @@ -1350,10 +1331,115 @@ namespace Xceed.Wpf.DataGrid m_sortDescriptions = null; m_groupDescriptions = null; - m_fieldNameMap.SetSource( this.DataGridControl, null ); + m_itemsSourcePropertyDescriptions.Clear(); + + this.InitializeItemPropertyMap( this.DataGridControl, null ); this.DetailDescription = null; - m_recyclingManager.Clear(); + if( synchronizeColumns ) + { + m_columnSynchronizationManager.Refresh(); + } + } + + private void InitializeItemPropertyMap( DataGridControl dataGridControl, DataGridDetailDescription detailDescription ) + { + using( m_itemPropertyMap.DeferMappingChanged() ) + { + if( ( dataGridControl == null ) || ( detailDescription == null ) || !dataGridControl.AreDetailsFlatten ) + { + m_itemPropertyMap.MasterItemProperties = null; + m_itemPropertyMap.DetailItemProperties = null; + } + else + { + var collectionView = dataGridControl.Items.SourceCollection as DataGridCollectionViewBase; + if( collectionView != null ) + { + m_itemPropertyMap.MasterItemProperties = collectionView.ItemProperties; + m_itemPropertyMap.DetailItemProperties = detailDescription.ItemProperties; + } + else + { + m_itemPropertyMap.MasterItemProperties = null; + m_itemPropertyMap.DetailItemProperties = null; + } + } + } + } + + private void UpdateColumns() + { + var detailDescription = this.DetailDescription; + var dataGridControl = this.DataGridControl; + var dataGridContext = this.DataGridContext; + + if( ( detailDescription != null ) && ( dataGridControl != null ) && ( dataGridContext != null ) ) + { + ItemsSourceHelper.ResetPropertyDescriptions( m_itemsSourcePropertyDescriptions, m_itemPropertyMap, dataGridControl, dataGridContext.Items ); + + if( this.AutoCreateColumns ) + { + ItemsSourceHelper.UpdateColumnsFromPropertyDescriptions( m_columnManager, dataGridControl.DefaultCellEditors, m_itemsSourcePropertyDescriptions, this.AutoCreateForeignKeyConfigurations ); + } + } + else + { + m_itemsSourcePropertyDescriptions.Clear(); + } + + if( detailDescription != null ) + { + // Ensure to update ForeignKeyDescriptions and ForeignKeyConfigurations when ItemProperties change on DetailDescription. + ForeignKeyConfiguration.UpdateColumnsForeignKeyConfigurationsFromDataGridCollectionView( + this.Columns, + detailDescription.ItemProperties, + this.AutoCreateForeignKeyConfigurations ); + } + } + + private void RegisterItemProperties( DataGridItemPropertyCollection itemProperties ) + { + if( itemProperties == null ) + return; + + CollectionChangedEventManager.AddListener( itemProperties, this ); + + foreach( var itemProperty in itemProperties ) + { + this.RegisterItemProperty( itemProperty ); + } + } + + private void UnregisterItemProperties( DataGridItemPropertyCollection itemProperties ) + { + if( itemProperties == null ) + return; + + foreach( var itemProperty in itemProperties ) + { + this.UnregisterItemProperty( itemProperty ); + } + + CollectionChangedEventManager.RemoveListener( itemProperties, this ); + } + + private void RegisterItemProperty( DataGridItemPropertyBase itemProperty ) + { + if( itemProperty == null ) + return; + + PropertyChangedEventManager.AddListener( itemProperty, this, DataGridItemPropertyBase.ItemPropertiesInternalPropertyName ); + this.RegisterItemProperties( itemProperty.ItemPropertiesInternal ); + } + + private void UnregisterItemProperty( DataGridItemPropertyBase itemProperty ) + { + if( itemProperty == null ) + return; + + this.UnregisterItemProperties( itemProperty.ItemPropertiesInternal ); + PropertyChangedEventManager.RemoveListener( itemProperty, this, DataGridItemPropertyBase.ItemPropertiesInternalPropertyName ); } private void UpdateColumnSortOrder() @@ -1385,77 +1471,129 @@ namespace Xceed.Wpf.DataGrid this.RequestDelayBringIntoViewAndFocusCurrent( AutoScrollCurrentItemSourceTriggers.ColumnsCollectionChanged ); this.UpdateColumnSortOrder(); - //Then call the method that will update the VisibleColumns - DataGridContext.HandleColumnsCollectionChanged( e, this.Columns, this.VisibleColumns as ReadOnlyColumnCollection, this.ColumnsByVisiblePosition ); - var detailDescription = this.DetailDescription; if( detailDescription != null ) { switch( e.Action ) { + case NotifyCollectionChangedAction.Add: + case NotifyCollectionChangedAction.Replace: case NotifyCollectionChangedAction.Reset: { ForeignKeyConfiguration.UpdateColumnsForeignKeyConfigurationsFromDataGridCollectionView( - this.Columns.FieldNameToColumnDictionary, + this.Columns, detailDescription.ItemProperties, this.AutoCreateForeignKeyConfigurations ); - - break; } + break; - case NotifyCollectionChangedAction.Add: - case NotifyCollectionChangedAction.Replace: - { - IList newItems = e.NewItems; - int count = newItems.Count; - Dictionary newColumns = new Dictionary( count ); + default: + break; + } + } + } - for( int i = 0; i < count; i++ ) - { - ColumnBase column = newItems[ i ] as ColumnBase; - newColumns.Add( column.FieldName, column ); - } + private void OnItemPropertiesCollectionChanged( DataGridItemPropertyCollection collection, NotifyCollectionChangedEventArgs e ) + { + var detailDescription = this.DetailDescription; + if( detailDescription == null ) + return; - ForeignKeyConfiguration.UpdateColumnsForeignKeyConfigurationsFromDataGridCollectionView( - newColumns, - detailDescription.ItemProperties, - this.AutoCreateForeignKeyConfigurations ); + var rootCollection = ItemsSourceHelper.GetRootCollection( collection ); + if( rootCollection == null ) + return; - break; - } + if( rootCollection == detailDescription.ItemProperties ) + { + if( e.Action == NotifyCollectionChangedAction.Reset ) + throw new NotSupportedException(); + + if( e.Action == NotifyCollectionChangedAction.Move ) + return; + + if( e.OldItems != null ) + { + foreach( DataGridItemPropertyBase itemProperty in e.OldItems ) + { + this.UnregisterItemProperty( itemProperty ); + } + } + + if( e.NewItems != null ) + { + foreach( DataGridItemPropertyBase itemProperty in e.NewItems ) + { + this.RegisterItemProperty( itemProperty ); + } + } + + this.UpdateColumns(); + } + else + { + Debug.Fail( "The collection is not linked to the detail configuration's item properties." ); + this.UnregisterItemProperties( collection ); + } + } + + private void OnItemPropertyPropertyChanged( DataGridItemPropertyBase itemProperty, PropertyChangedEventArgs e ) + { + var detailDescription = this.DetailDescription; + if( detailDescription == null ) + return; + + var rootCollection = ItemsSourceHelper.GetRootCollection( itemProperty ); + if( rootCollection == null ) + return; + + if( rootCollection != detailDescription.ItemProperties ) + { + Debug.Fail( "The collection is not linked to the detail configuration's item properties." ); + this.UnregisterItemProperty( itemProperty ); + return; + } + + if( string.IsNullOrEmpty( e.PropertyName ) || ( e.PropertyName == DataGridItemPropertyBase.ItemPropertiesInternalPropertyName ) ) + { + var itemProperties = itemProperty.ItemPropertiesInternal; + if( itemProperties != null ) + { + this.UnregisterItemProperties( itemProperties ); + this.RegisterItemProperties( itemProperties ); + this.UpdateColumns(); } } } private void HandleCurrentColumnRemove( NotifyCollectionChangedEventArgs e ) { - bool removeCurrentColumn = false; - ColumnBase currentColumn = this.CurrentColumn; + var currentColumn = this.CurrentColumn; + if( currentColumn == null ) + return; + + var removeCurrentColumn = false; if( e.Action == NotifyCollectionChangedAction.Reset ) { - //Reset means that collection was cleared. - removeCurrentColumn = true; + removeCurrentColumn = !this.Columns.Contains( currentColumn ); } - else if( ( e.Action == NotifyCollectionChangedAction.Remove ) && ( e.OldItems.Contains( currentColumn ) == true ) ) + else if( ( e.Action == NotifyCollectionChangedAction.Remove ) && ( e.OldItems.Contains( currentColumn ) ) ) { //Remove of at least the current column removeCurrentColumn = true; } - else if( ( e.Action == NotifyCollectionChangedAction.Replace ) && ( e.OldItems.Contains( currentColumn ) == true ) - && ( e.NewItems.Contains( currentColumn ) == false ) ) + else if( ( e.Action == NotifyCollectionChangedAction.Replace ) && ( e.OldItems.Contains( currentColumn ) ) && ( !e.NewItems.Contains( currentColumn ) ) ) { //Replace in which at least the current column was "replaced" by another (current column not present in new items ) removeCurrentColumn = true; } //If we computed that current columns should be cleared - if( removeCurrentColumn == true ) + if( removeCurrentColumn ) { //reset current column. this.CurrentColumn = DataGridContext.GetClosestColumn( currentColumn, this.ColumnsByVisiblePosition ); } - } private void OnDetailConfigurationsChanged( object sender, NotifyCollectionChangedEventArgs e ) @@ -1479,79 +1617,61 @@ namespace Xceed.Wpf.DataGrid private void RequestDelayBringIntoViewAndFocusCurrent( AutoScrollCurrentItemSourceTriggers trigger ) { - var handler = this.RequestingDelayBringIntoViewAndFocusCurrent; - if( handler == null ) - return; - - handler.Invoke( this, new RequestingDelayBringIntoViewAndFocusCurrentEventArgs( trigger ) ); } #region IWeakEventListener Members bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) + { + return this.OnReceiveWeakEvent( managerType, sender, e ); + } + + private bool OnReceiveWeakEvent( Type managerType, object sender, EventArgs e ) { //check if the event comes from a INotifyCollectionChanged collection if( managerType == typeof( CollectionChangedEventManager ) ) { - NotifyCollectionChangedEventArgs ncce = ( NotifyCollectionChangedEventArgs )e; + var eventArgs = ( NotifyCollectionChangedEventArgs )e; if( sender is DetailConfigurationCollection ) { - this.OnDetailConfigurationsChanged( sender, ncce ); - return true; + this.OnDetailConfigurationsChanged( sender, eventArgs ); } else if( sender is SortDescriptionCollection ) { - this.SortDescriptions_CollectionChanged( sender, ncce ); - return true; + this.SortDescriptions_CollectionChanged( sender, eventArgs ); } else if( sender is ObservableCollection ) { - this.GroupDescriptions_CollectionChanged( sender, ncce ); - return true; + this.GroupDescriptions_CollectionChanged( sender, eventArgs ); } else if( sender is DataGridDetailDescriptionCollection ) { - var detailDescription = this.DetailDescription; - if( detailDescription != null ) - { - DetailConfiguration.SynchronizeDetailConfigurations( - detailDescription.DetailDescriptions, - this.DetailConfigurations, - this.AutoCreateDetailConfigurations, - this.AutoCreateForeignKeyConfigurations, - this.AutoRemoveColumnsAndDetailConfigurations ); - } - - return true; } else if( sender is DataGridItemPropertyCollection ) { - // Ensure to update ForeignKeyDescriptions and ForeignKeyConfigurations - // when ItemProperties change on DetailDescription - var detailDescription = this.DetailDescription; - if( detailDescription != null ) - { - ForeignKeyConfiguration.UpdateColumnsForeignKeyConfigurationsFromDataGridCollectionView( - this.Columns.FieldNameToColumnDictionary, - detailDescription.ItemProperties, - this.AutoCreateForeignKeyConfigurations ); - } - return true; + this.OnItemPropertiesCollectionChanged( ( DataGridItemPropertyCollection )sender, eventArgs ); } } - else if( managerType == typeof( VisibilityChangedEventManager ) ) + else if( managerType == typeof( PropertyChangedEventManager ) ) { - var wrappedEventArgs = ( ColumnCollection.WrappedEventEventArgs )e; - - DataGridContext.UpdateVisibleColumns( - this.Columns, this.VisibleColumns as ReadOnlyColumnCollection, this.ColumnsByVisiblePosition, - new object[] { wrappedEventArgs.WrappedSender }, wrappedEventArgs.WrappedEventArgs as ColumnVisiblePositionChangedEventArgs ); + var eventArgs = ( PropertyChangedEventArgs )e; - return true; + if( sender is DataGridItemPropertyBase ) + { + this.OnItemPropertyPropertyChanged( ( DataGridItemPropertyBase )sender, eventArgs ); + } + } + else if( managerType == typeof( ViewChangedEventManager ) ) + { + this.InitializeItemPropertyMap( this.DataGridControl, this.DetailDescription ); + } + else + { + return false; } - return false; + return true; } #endregion @@ -1560,31 +1680,35 @@ namespace Xceed.Wpf.DataGrid public void BeginInit() { - m_beginInitCount++; + m_initCount++; + if( m_initCount != 1 ) + return; - //It is determined at construction of the DetailConfiguration if it is synchronized with its parent, therefore, I can assume it is set appropriatly here - if( m_columnsInitDisposable == null ) - { - m_columnsInitDisposable = this.Columns.DeferColumnAdditionMessages(); - } + Debug.Assert( m_deferColumnsLayoutUpdate == null ); + m_deferColumnsLayoutUpdate = m_columnManager.DeferUpdate(); + + m_deferColumnsNotifications = this.Columns.DeferNotifications(); } public void EndInit() { - if( m_beginInitCount > 0 ) - m_beginInitCount--; + m_initCount--; + if( m_initCount != 0 ) + return; - if( m_beginInitCount == 0 ) - { - if( m_columnsInitDisposable != null ) - { - m_columnsInitDisposable.Dispose(); - m_columnsInitDisposable = null; - } - } + var columnsNotificationsDisposable = m_deferColumnsNotifications; + m_deferColumnsNotifications = null; + columnsNotificationsDisposable.Dispose(); + + Debug.Assert( m_deferColumnsLayoutUpdate != null ); + var columnsUpdateDisposable = m_deferColumnsLayoutUpdate; + m_deferColumnsLayoutUpdate = null; + columnsUpdateDisposable.Dispose(); } - private int m_beginInitCount = 0; + private int m_initCount = 0; + private IDisposable m_deferColumnsLayoutUpdate; //null + private IDisposable m_deferColumnsNotifications; //null #endregion @@ -1594,20 +1718,18 @@ namespace Xceed.Wpf.DataGrid private void OnPropertyChanged( string propertyName ) { - if( this.PropertyChanged != null ) - { - this.PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) ); - } + var handler = this.PropertyChanged; + if( handler == null ) + return; + + handler.Invoke( this, new PropertyChangedEventArgs( propertyName ) ); } #endregion private bool m_shouldCreateColumns = true; - private IDisposable m_columnsInitDisposable; // = null private bool m_defaultHeadersFootersAdded; // = false - private readonly RecyclingManager m_recyclingManager = new RecyclingManager(); - private sealed class DetailConfigurationUpdateColumnSortCommand : UpdateColumnSortCommand { private static void ThrowIfDetailsNotFlatten( DetailConfiguration detailConfiguration ) @@ -1758,7 +1880,7 @@ namespace Xceed.Wpf.DataGrid if( !synchronizationContext.Own ) return; - if( !detailConfiguration.IsAttachedToDetailDescription ) + if( detailConfiguration.DetailDescription == null ) return; var dataGridControl = detailConfiguration.DataGridControl; @@ -1775,28 +1897,29 @@ namespace Xceed.Wpf.DataGrid using( this.DeferResortHelper( detailConfiguration ) ) { - this.SynchronizeDetailSortDescriptions( masterSortDescriptions, detailSortDescriptions, detailConfiguration.ItemPropertyMap ); + this.SynchronizeDetailSortDescriptions( masterSortDescriptions, detailSortDescriptions, detailConfiguration ); } } - private void SynchronizeDetailSortDescriptions( SortDescriptionCollection masterSortDescriptions, SortDescriptionCollection detailSortDescriptions, - FieldNameMap itemPropertyMap ) + private void SynchronizeDetailSortDescriptions( SortDescriptionCollection masterSortDescriptions, SortDescriptionCollection detailSortDescriptions, DetailConfiguration detailConfiguration ) { ColumnSortCommand.ThrowIfNull( masterSortDescriptions, "masterSortDescriptions" ); ColumnSortCommand.ThrowIfNull( detailSortDescriptions, "detailSortDescriptions" ); + + var itemPropertyMap = detailConfiguration.ItemPropertyMap; ColumnSortCommand.ThrowIfNull( itemPropertyMap, "itemPropertyMap" ); - int masterSortDescriptionsCount = masterSortDescriptions.Count; + var masterSortDescriptionsCount = masterSortDescriptions.Count; if( masterSortDescriptionsCount > 0 ) { - int insertionIndex = 0; + var insertionIndex = 0; for( int i = 0; i < masterSortDescriptionsCount; i++ ) { var sortDescription = masterSortDescriptions[ i ]; + var detailPropertyName = default( string ); - string detailPropertyName; - if( !itemPropertyMap.TryGetItemPropertyName( sortDescription.PropertyName, out detailPropertyName ) ) + if( !DataGridItemPropertyMapHelper.TryGetDetailColumnName( itemPropertyMap, sortDescription.PropertyName, out detailPropertyName ) ) continue; var detailDirection = sortDescription.Direction; @@ -1872,16 +1995,22 @@ namespace Xceed.Wpf.DataGrid protected override string GetColumnName( ColumnBase column ) { var detailConfiguration = this.DetailConfiguration; - if( detailConfiguration == null ) + if( ( detailConfiguration == null ) || ( column == null ) ) return null; - var fieldNameMap = detailConfiguration.ItemPropertyMap; - string fieldName; - - if( !fieldNameMap.TryGetItemPropertyName( column, out fieldName ) ) - return null; + var itemPropertyMap = detailConfiguration.ItemPropertyMap; + if( ( itemPropertyMap != null ) && itemPropertyMap.IsMapping ) + { + string fieldName; + if( DataGridItemPropertyMapHelper.TryGetDetailColumnName( itemPropertyMap, column.FieldName, out fieldName ) ) + return fieldName; + } + else + { + return column.FieldName; + } - return fieldName; + return null; } protected override GroupDescription GetGroupDescription( ColumnBase column ) @@ -1937,99 +2066,5 @@ namespace Xceed.Wpf.DataGrid } } } - - private sealed class FieldNameMapProxy : FieldNameMap, INotifyCollectionChanged - { - #region Source Private Property - - private FieldNameMap Source - { - get - { - return m_source; - } - set - { - if( value == m_source ) - return; - - var oldSource = m_source as INotifyCollectionChanged; - if( oldSource != null ) - { - oldSource.CollectionChanged -= new NotifyCollectionChangedEventHandler( this.OnSourceCollectionChanged ); - } - - m_source = value; - - var newSource = m_source as INotifyCollectionChanged; - if( newSource != null ) - { - newSource.CollectionChanged += new NotifyCollectionChangedEventHandler( this.OnSourceCollectionChanged ); - } - - this.RaiseCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Reset ) ); - } - } - - private FieldNameMap m_source; - - #endregion - - protected override bool TryGetSource( string targetName, out string sourceName ) - { - var source = this.Source; - if( source != null ) - return source.TryGetItemPropertyName( targetName, out sourceName ); - - return base.TryGetSource( targetName, out sourceName ); - } - - protected override bool TryGetTarget( string sourceName, out string targetName ) - { - var source = this.Source; - if( source != null ) - return source.TryGetColumnFieldName( sourceName, out targetName ); - - return base.TryGetTarget( sourceName, out targetName ); - } - - internal void SetSource( DataGridControl dataGridControl, DataGridDetailDescription detailDescription ) - { - if( ( dataGridControl == null ) || ( detailDescription == null ) || ( !dataGridControl.AreDetailsFlatten ) ) - { - this.Source = null; - } - else - { - var map = this.Source as ItemPropertyNameMap; - var itemProperties = detailDescription.ItemProperties; - - if( ( map == null ) || ( map.ItemProperties != detailDescription.ItemProperties ) ) - { - this.Source = new ItemPropertyNameMap( itemProperties ); - } - } - } - - private void OnSourceCollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) - { - this.RaiseCollectionChanged( e ); - } - - #region INotifyCollectionChanged Members - - public event NotifyCollectionChangedEventHandler CollectionChanged; - - private void RaiseCollectionChanged( NotifyCollectionChangedEventArgs e ) - { - var handler = this.CollectionChanged; - if( handler == null ) - return; - - handler.Invoke( this, e ); - } - - #endregion - } } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DetailConfigurationCollection.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DetailConfigurationCollection.cs index b3cf167b..22632842 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DetailConfigurationCollection.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DetailConfigurationCollection.cs @@ -23,8 +23,6 @@ namespace Xceed.Wpf.DataGrid { internal class DetailConfigurationCollection : ObservableCollection, IWeakEventListener { - #region CONSTRUCTORS - internal DetailConfigurationCollection( DataGridControl dataGridControl, DetailConfiguration parentDetailConfiguration ) : base() { @@ -32,7 +30,38 @@ namespace Xceed.Wpf.DataGrid this.ParentDetailConfiguration = parentDetailConfiguration; } - #endregion CONSTRUCTORS + #region DataGridControl Property + + internal DataGridControl DataGridControl + { + get + { + return m_dataGridControl; + } + set + { + if( m_dataGridControl == value ) + return; + + m_dataGridControl = value; + + this.OnPropertyChanged( new PropertyChangedEventArgs( "DataGridControl" ) ); + } + } + + private DataGridControl m_dataGridControl; + + #endregion + + #region ParentDetailConfiguration Property + + internal DetailConfiguration ParentDetailConfiguration + { + get; + set; + } + + #endregion public DetailConfiguration this[ string relationName ] { @@ -107,6 +136,11 @@ namespace Xceed.Wpf.DataGrid internal event EventHandler DetailVisibilityChanged; bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) + { + return this.OnReceiveWeakEvent( managerType, sender, e ); + } + + protected virtual bool OnReceiveWeakEvent( Type managerType, object sender, EventArgs e ) { if( managerType == typeof( DetailVisibilityChangedEventManager ) ) { @@ -121,38 +155,5 @@ namespace Xceed.Wpf.DataGrid } #endregion - - #region DataGridControl Property - - internal DataGridControl DataGridControl - { - get - { - return m_dataGridControl; - } - set - { - if( m_dataGridControl == value ) - return; - - m_dataGridControl = value; - - this.OnPropertyChanged( new PropertyChangedEventArgs( "DataGridControl" ) ); - } - } - - private DataGridControl m_dataGridControl; - - #endregion - - #region ParentDetailConfiguration Property - - internal DetailConfiguration ParentDetailConfiguration - { - get; - set; - } - - #endregion } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DetailConfigurationSelector.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DetailConfigurationSelector.cs new file mode 100644 index 00000000..fca7f661 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DetailConfigurationSelector.cs @@ -0,0 +1,26 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +namespace Xceed.Wpf.DataGrid +{ + public abstract class DetailConfigurationSelector + { + internal virtual DetailConfiguration SelectDetailConfiguration( string relationName, DataGridDetailDescription dataGridDetailDescription ) + { + return null; + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridControlTraceSources.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridControlTraceSources.cs new file mode 100644 index 00000000..1e48c1d8 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridControlTraceSources.cs @@ -0,0 +1,68 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System.Diagnostics; +using System.Threading; + +namespace Xceed.Wpf.DataGrid.Diagnostics +{ + internal static class DataGridControlTraceSources + { + #region CollectionViewSource Property + + internal static DataGridTraceSource CollectionViewSource + { + get + { + return DataGridControlTraceSources.DataGridTraceSource; + } + } + + #endregion + + #region ItemContainerGeneratorSource Property + + internal static DataGridTraceSource ItemContainerGeneratorSource + { + get + { + return DataGridControlTraceSources.DataGridTraceSource; + } + } + + #endregion + + #region DataSource Private Property + + private static DataGridTraceSource DataGridTraceSource + { + get + { + if( s_traceSource == null ) + { + var source = new DataGridTraceSource( new TraceSource( "Xceed.Wpf.DataGrid" ) ); + Interlocked.CompareExchange( ref s_traceSource, source, null ); + } + + return s_traceSource; + } + } + + private static DataGridTraceSource s_traceSource; //null + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridTraceArg.Generic.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridTraceArg.Generic.cs new file mode 100644 index 00000000..ffff83e2 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridTraceArg.Generic.cs @@ -0,0 +1,86 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Globalization; +using System.Windows; + +namespace Xceed.Wpf.DataGrid.Diagnostics +{ + internal class DataGridTraceArg : DataGridTraceArg + { + internal DataGridTraceArg( T value ) + { + m_value = value; + } + + protected override string FormatOutput( CultureInfo culture ) + { + if( object.ReferenceEquals( m_value, null ) ) + return ""; + + var formattable = m_value as IFormattable; + if( formattable != null ) + return formattable.ToString( null, culture ); + + var valueType = m_value.GetType(); + if( valueType.IsGenericType && ( valueType.GetGenericTypeDefinition() == typeof( Nullable<> ) ) ) + { + valueType = Nullable.GetUnderlyingType( valueType ); + } + + if( valueType.IsEnum ) + return m_value.ToString(); + + if( valueType.IsPrimitive || ( typeof( string ) == valueType ) ) + return string.Format( culture, "{0}", m_value ); + + var hashCode = m_value.GetHashCode(); + var name = default( string ); + + if( m_value is DataGridControl ) + { + var dataGridControl = m_value as DataGridControl; + + name = dataGridControl.GridUniqueName; + + if( string.IsNullOrEmpty( name ) ) + { + name = dataGridControl.Name; + } + } + else if( m_value is FrameworkElement ) + { + var fe = m_value as FrameworkElement; + + name = fe.Name; + } + else if( m_value is FrameworkContentElement ) + { + var fce = m_value as FrameworkContentElement; + + name = fce.Name; + } + + if( !string.IsNullOrEmpty( name ) ) + return string.Format( culture, "('{2}' -> {0}, <{1}>)", hashCode, valueType, name ); + + return string.Format( culture, "({0}, <{1}>)", hashCode, valueType ); + } + + private readonly T m_value; + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridTraceArg.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridTraceArg.cs new file mode 100644 index 00000000..328b0853 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridTraceArg.cs @@ -0,0 +1,34 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System.Globalization; + +namespace Xceed.Wpf.DataGrid.Diagnostics +{ + internal abstract class DataGridTraceArg + { + protected abstract string FormatOutput( CultureInfo culture ); + + public sealed override string ToString() + { + var output = this.FormatOutput( CultureInfo.InvariantCulture ); + if( string.IsNullOrEmpty( output ) ) + return string.Empty; + + return output; + } + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridTraceArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridTraceArgs.cs new file mode 100644 index 00000000..0297d39f --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridTraceArgs.cs @@ -0,0 +1,145 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System.Globalization; + +namespace Xceed.Wpf.DataGrid.Diagnostics +{ + internal static class DataGridTraceArgs + { + internal static DataGridTraceArg Action( T value ) + { + return new TraceArg( "Action", value ); + } + + internal static DataGridTraceArg DataSource( T value ) + { + return new TraceArg( "DataSource", value ); + } + + internal static DataGridTraceArg DataGridControl( T value ) + { + return new TraceArg( "DataGridControl", value ); + } + + internal static DataGridTraceArg Generator( T value ) + { + return new TraceArg( "ItemContainerGenerator", value ); + } + + internal static DataGridTraceArg Count( T value ) + { + return new TraceArg( "Count", value ); + } + + internal static DataGridTraceArg ItemCount( T value ) + { + return new TraceArg( "ItemCount", value ); + } + + internal static DataGridTraceArg Container( T value ) + { + return new TraceArg( "Container", value ); + } + + internal static DataGridTraceArg Group( T value ) + { + return new TraceArg( "Group", value ); + } + + internal static DataGridTraceArg Index( T value ) + { + return new TraceArg( "Index", value ); + } + + internal static DataGridTraceArg GeneratorIndex( T value ) + { + return new TraceArg( "GIndex", value ); + } + + internal static DataGridTraceArg From( T value ) + { + return new TraceArg( "From", value ); + } + + internal static DataGridTraceArg To( T value ) + { + return new TraceArg( "To", value ); + } + + internal static DataGridTraceArg Item( T value ) + { + return new TraceArg( "Item", value ); + } + + internal static DataGridTraceArg Node( T value ) + { + return new TraceArg( "Node", value ); + } + + internal static DataGridTraceArg NextNode( T value ) + { + return new TraceArg( "NNode", value ); + } + + internal static DataGridTraceArg PreviousNode( T value ) + { + return new TraceArg( "PNode", value ); + } + + internal static DataGridTraceArg LastNode( T value ) + { + return new TraceArg( "LNode", value ); + } + + internal static DataGridTraceArg Value( T value ) + { + return new TraceArg( "Value", value ); + } + + #region TraceArg Private Class + + private sealed class TraceArg : DataGridTraceArg + { + internal TraceArg( string label, T value ) + : base( value ) + { + m_label = label; + } + + protected sealed override string FormatOutput( CultureInfo culture ) + { + var label = m_label; + var value = base.FormatOutput( culture ); + + if( string.IsNullOrEmpty( label ) ) + return value; + + if( value == null ) + return string.Format( "{0}: ", label ); + + if( value.Length == 0 ) + return string.Format( "{0}: ''", label ); + + return string.Format( "{0}: {1}", label, value ); + } + + private readonly string m_label; + } + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridTraceEventIdEnum.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridTraceEventIdEnum.cs new file mode 100644 index 00000000..3fd28a1e --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridTraceEventIdEnum.cs @@ -0,0 +1,80 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + + +namespace Xceed.Wpf.DataGrid.Diagnostics +{ + internal enum DataGridTraceEventId + { + CustomItemContainerGenerator_ApplyGroupChanges = 0, + CustomItemContainerGenerator_CleanupGenerator, + CustomItemContainerGenerator_CloseDetailsForItem, + CustomItemContainerGenerator_CollapseDetails, + CustomItemContainerGenerator_CollapseGroup, + CustomItemContainerGenerator_ContainerFromIndex, + CustomItemContainerGenerator_ContainerFromItem, + CustomItemContainerGenerator_CreateDetailsForItem, + CustomItemContainerGenerator_CreateDetailsHelper, + CustomItemContainerGenerator_EnsureNodeTreeCreated, + CustomItemContainerGenerator_ExpandDetails, + CustomItemContainerGenerator_ExpandGroup, + CustomItemContainerGenerator_FindIndexForItem, + CustomItemContainerGenerator_GenerateNextLocalContainer, + CustomItemContainerGenerator_GenerateStickyFootersForDetail, + CustomItemContainerGenerator_GenerateStickyHeadersForDetail, + CustomItemContainerGenerator_GenPosArraysRemoveAt, + CustomItemContainerGenerator_GetGroupFromItem, + CustomItemContainerGenerator_GetGroupIndex, + CustomItemContainerGenerator_GetRealizedContainerForIndex, + CustomItemContainerGenerator_GetRealizedIndexForContainer, + CustomItemContainerGenerator_HandleDetailReset, + CustomItemContainerGenerator_HandleGlobalItemsReset, + CustomItemContainerGenerator_HandleHeadersFootersAddition, + CustomItemContainerGenerator_HandleHeadersFootersRemoveMoveReplace, + CustomItemContainerGenerator_HandleItemAddition, + CustomItemContainerGenerator_HandleItemReset, + CustomItemContainerGenerator_HandleSameLevelGroupAddition, + CustomItemContainerGenerator_HandleSameLevelGroupMove, + CustomItemContainerGenerator_HandleSameLevelGroupRemove, + CustomItemContainerGenerator_HandleSameLevelGroupReset, + CustomItemContainerGenerator_IItemContainerGenerator_GenerateNext, + CustomItemContainerGenerator_IItemContainerGenerator_Remove, + CustomItemContainerGenerator_IndexFromItem, + CustomItemContainerGenerator_IsGroupExpanded, + CustomItemContainerGenerator_ItemFromContainer, + CustomItemContainerGenerator_ItemFromIndex, + CustomItemContainerGenerator_MoveGeneratorBackward, + CustomItemContainerGenerator_MoveGeneratorForward, + CustomItemContainerGenerator_OnDetailConfigurationsChanged, + CustomItemContainerGenerator_OnDetailGeneratorContentChanged, + CustomItemContainerGenerator_OnGeneratorNodeExpansionStateChanged, + CustomItemContainerGenerator_OnGeneratorNodeGroupsCollectionChanged, + CustomItemContainerGenerator_OnGeneratorNodeHeadersFootersCollectionChanged, + CustomItemContainerGenerator_OnGeneratorNodeItemsCollectionChanged, + CustomItemContainerGenerator_OnGroupGeneratorNodeIsExpandedChanged, + CustomItemContainerGenerator_OnGroupGeneratorNodeIsExpandedChanging, + CustomItemContainerGenerator_OnGroupsChanged, + CustomItemContainerGenerator_OnItemsChanged, + CustomItemContainerGenerator_ProcessGroupRemoval, + CustomItemContainerGenerator_RemapFloatingDetails, + CustomItemContainerGenerator_SetupInitialItemsNodes, + CustomItemContainerGenerator_ToggleDetails, + CustomItemContainerGenerator_ToggleGroupExpansion, + CustomItemContainerGenerator_UpdateFooters, + CustomItemContainerGenerator_UpdateGenPosToIndexList, + CustomItemContainerGenerator_UpdateHeaders, + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridTraceMessages.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridTraceMessages.cs new file mode 100644 index 00000000..a1d04d9b --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridTraceMessages.cs @@ -0,0 +1,71 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Xceed.Wpf.DataGrid.Diagnostics +{ + internal static class DataGridTraceMessages + { + internal const string CannotCollapseDetail = "Cannot collapse the detail."; + internal const string CannotExpandDetail = "Cannot expand the detail."; + internal const string CannotProcessOnReset = "Cannot process while resetting."; + internal const string CannotRemapDetails = "Cannot remap details when deferred."; + internal const string CollapsedItemAdded = "Item(s) added under a collapsed node."; + internal const string CollapsingDetail = "Collapsing a detail."; + internal const string ContainerAdded = "The container was added."; + internal const string ContainerFound = "The container was found."; + internal const string ContainerGenerated = "A container was generated."; + internal const string ContainerIsInDetail = "The container is located in a detail."; + internal const string ContainerNotFound = "The container was not found."; + internal const string ContainerRemoved = "The container was removed."; + internal const string DetailAlreadyCollapsed = "The detail is already collapsed."; + internal const string DetailAlreadyExpanded = "The detail is already expanded."; + internal const string DetailExpanded = "The detail was expanded."; + internal const string DetailCollapsed = "The detail was collapsed."; + internal const string DetailExpected = "Detail expected."; + internal const string DetailIsFloating = "The detail is floating."; + internal const string DetailNodeAdded = "Detail node(s) added."; + internal const string DetailNodeNotFound = "The detail node was not found."; + internal const string DetailNotFound = "The detail was not found."; + internal const string DetailNotSupported = "Details are not supported."; + internal const string EmptyTree = "There is no node."; + internal const string GroupFound = "The group was found."; + internal const string GroupNodeAdded = "Group node(s) added."; + internal const string GroupNodeRemoved = "Group node(s) removed."; + internal const string GroupNotFound = "The group was not found."; + internal const string InhibiterAlreadySet = "An inhibiter is already set."; + internal const string IndexFound = "The index was found."; + internal const string IndexUpdated = "The index was updated."; + internal const string ItemAdded = "Item(s) added."; + internal const string ItemFound = "The item was found."; + internal const string ItemNotBelongingToGenerator = "The item does not belong to the generator."; + internal const string ItemNotBelongingToNode = "The item does not belong to the node."; + internal const string ItemNotFound = "The item was not found."; + internal const string ItemNotFoundOrCollapsed = "The item was not found or is under a collapsed node."; + internal const string NewStartNode = "New start node."; + internal const string NewTreeCreated = "New tree node created."; + internal const string NodeFound = "The node was found."; + internal const string NodeIsCollapsed = "The node is collapsed."; + internal const string NodeIsNotTheCurrentNode = "Node is not the current one."; + internal const string RemapDetailNodes = "Remap details nodes."; + internal const string RemapZombieDetail = "Master item not found for detail."; + internal const string UnexpectedNode = "Unexpected node."; + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridTraceSource.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridTraceSource.cs new file mode 100644 index 00000000..647f3c32 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Diagnostics/DataGridTraceSource.cs @@ -0,0 +1,201 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading; + +namespace Xceed.Wpf.DataGrid.Diagnostics +{ + internal class DataGridTraceSource + { + #region Static Fields + + internal readonly IDisposable NoTrace = new EmptyDisposable(); + + #endregion + + internal DataGridTraceSource( TraceSource traceSource ) + { + if( traceSource == null ) + throw new ArgumentNullException( "traceSource" ); + + m_traceSource = traceSource; + } + + internal bool ShouldTrace( TraceEventType eventType ) + { +#if TRACE + var listeners = m_traceSource.Listeners; + if( ( listeners == null ) || ( listeners.Count <= 0 ) ) + return false; + + var sourceSwitch = m_traceSource.Switch; + + return ( sourceSwitch != null ) + && ( sourceSwitch.ShouldTrace( eventType ) ); +#else + return false; +#endif + } + + internal bool ShouldTraceBlock() + { + return ( this.ShouldTrace( TraceEventType.Start ) ) + || ( this.ShouldTrace( TraceEventType.Stop ) ); + } + + internal IDisposable TraceBlock( DataGridTraceEventId eventId, string message, IEnumerable args ) + { + if( this.ShouldTrace( TraceEventType.Start ) ) + { + this.TraceEventCore( TraceEventType.Start, eventId, message, args ); + } + + if( this.ShouldTrace( TraceEventType.Stop ) ) + return new TraceBlockEndDisposable( this, eventId, message, args ); + + return this.NoTrace; + } + + [Conditional( "TRACE" )] + internal void TraceEvent( TraceEventType eventType, DataGridTraceEventId eventId, string message, IEnumerable args ) + { + if( !this.ShouldTrace( eventType ) ) + return; + + this.TraceEventCore( eventType, eventId, message, args ); + } + + private void TraceEventCore( TraceEventType eventType, DataGridTraceEventId eventId, string message, IEnumerable args ) + { + var format = DataGridTraceSource.Format( args ); + + if( string.IsNullOrEmpty( message ) ) + { + if( string.IsNullOrEmpty( format ) ) + { + DataGridTraceSource.TraceEvent( m_traceSource, eventType, ( int )eventId, null ); + } + else + { + DataGridTraceSource.TraceEvent( m_traceSource, eventType, ( int )eventId, format ); + } + } + else + { + if( string.IsNullOrEmpty( format ) ) + { + DataGridTraceSource.TraceEvent( m_traceSource, eventType, ( int )eventId, message ); + } + else + { + DataGridTraceSource.TraceEvent( m_traceSource, eventType, ( int )eventId, message + " | " + format ); + } + } + } + + private static void TraceEvent( TraceSource source, TraceEventType eventType, int eventId, string message ) + { + if( string.IsNullOrEmpty( message ) ) + { + source.TraceEvent( eventType, eventId ); + } + else + { + source.TraceEvent( eventType, eventId, message ); + } + + if( Debugger.IsAttached ) + { + source.Flush(); + } + } + + private static string Format( IEnumerable args ) + { + if( ( args == null ) || !args.Any() ) + return null; + + var sb = new StringBuilder( 128 ); + + foreach( var arg in args ) + { + var value = arg.ToString(); + + if( string.IsNullOrEmpty( value ) ) + continue; + + if( sb.Length > 0 ) + { + sb.Append( "; " ); + } + + sb.Append( value ); + } + + return sb.ToString(); + } + + private readonly TraceSource m_traceSource; + + #region TraceBlockEndDisposable Private Class + + private sealed class TraceBlockEndDisposable : IDisposable + { + internal TraceBlockEndDisposable( DataGridTraceSource owner, DataGridTraceEventId eventId, string message, IEnumerable args ) + { + if( owner == null ) + throw new ArgumentNullException( "owner" ); + + m_owner = owner; + m_eventId = eventId; + m_message = message; + m_args = args; + } + + void IDisposable.Dispose() + { + var owner = Interlocked.Exchange( ref m_owner, null ); + if( owner == null ) + return; + + owner.TraceEventCore( TraceEventType.Stop, m_eventId, m_message, m_args ); + } + + private DataGridTraceSource m_owner; + private readonly DataGridTraceEventId m_eventId; + private readonly string m_message; + private readonly IEnumerable m_args; + } + + #endregion + + #region EmptyDisposable Private Class + + private sealed class EmptyDisposable : IDisposable + { + void IDisposable.Dispose() + { + } + } + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DropMarkAdorner.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DropMarkAdorner.cs index f5b8a937..a4707270 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DropMarkAdorner.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DropMarkAdorner.cs @@ -23,37 +23,27 @@ using Xceed.Wpf.DataGrid.Views; namespace Xceed.Wpf.DataGrid { - internal class DropMarkAdorner : Adorner + internal sealed class DropMarkAdorner : Adorner { // A null value for the pen parameter means that the adorner will not show any visual cue. - public DropMarkAdorner( UIElement adornedElement, Pen pen, DropMarkOrientation orientation ) + internal DropMarkAdorner( UIElement adornedElement, Pen pen, DropMarkOrientation orientation ) : base( adornedElement ) { Debug.Assert( orientation != DropMarkOrientation.Default, "A DropMarkAdorner without a specific orientation should virtually never happen. The only known way to do this would be to have a grid element not hosted in a DataGridControl. The DropMarkAdorner should react well to this nonetheless." ); m_pen = pen; m_orientation = orientation; + m_render = ( pen != null ); this.IsHitTestVisible = false; } - public DropMarkAlignment Alignment - { - get - { - return m_alignment; - } - } - - // This Property does not use the Alignment paradigm. It allows to manually set the position of the drop mark. #region HorizontalPosition Property public static readonly DependencyProperty HorizontalPositionProperty = DependencyProperty.Register( "HorizontalPosition", typeof( double ), typeof( DropMarkAdorner ), - new FrameworkPropertyMetadata( - 0d, - new PropertyChangedCallback( DropMarkAdorner.OnHorizontalPositionChanged ) ) ); + new FrameworkPropertyMetadata( 0d, new PropertyChangedCallback( DropMarkAdorner.OnHorizontalPositionChanged ) ) ); public double HorizontalPosition { @@ -69,164 +59,140 @@ namespace Xceed.Wpf.DataGrid private static void OnHorizontalPositionChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { - DropMarkAdorner adorner = sender as DropMarkAdorner; - - if( adorner == null ) + var self = sender as DropMarkAdorner; + if( self == null ) return; - adorner.UpdatePosition(); + self.Update(); } #endregion - public void ForceAlignment( DropMarkAlignment alignment ) - { - m_alignment = alignment; - } + #region Alignment Property - public void UpdateAlignment( Point mousePosition ) + internal DropMarkAlignment Alignment { - DropMarkAlignment alignment = DropMarkAlignment.Near; - - if( m_orientation == DropMarkOrientation.Horizontal ) + get { - // A horizontal drop mark is either displayed at the top or at the bottom of the AdornedElement. - Rect hitTestRect = new Rect( 0d, 0d, this.AdornedElement.RenderSize.Width, this.AdornedElement.RenderSize.Height / 2 ); - - if( hitTestRect.Contains( mousePosition ) ) - { - alignment = DropMarkAlignment.Near; - } - else - { - alignment = DropMarkAlignment.Far; - } + return m_alignment; } - else + set { - // A vertical drop mark is either displayed at the left or at the right of the AdornedElement. - Rect hitTestRect = new Rect( 0d, 0d, this.AdornedElement.RenderSize.Width / 2, this.AdornedElement.RenderSize.Height ); - - if( hitTestRect.Contains( mousePosition ) ) - { - alignment = DropMarkAlignment.Near; - } - else - { - alignment = DropMarkAlignment.Far; - } - } + if( value == m_alignment ) + return; - if( alignment != m_alignment ) - { - m_alignment = alignment; - this.UpdatePosition(); + m_alignment = value; + + this.Update(); } } - protected override Size MeasureOverride( Size constraint ) - { - this.AdornedElement.Measure( constraint ); + private DropMarkAlignment m_alignment = DropMarkAlignment.ExplicitPosition; + + #endregion - Size size = Size.Empty; + #region AdornerLayout Private Property - if( m_pen != null ) + private AdornerLayer AdornerLayer + { + get { - switch( m_orientation ) - { - case DropMarkOrientation.Default: - case DropMarkOrientation.Vertical: - size = new Size( m_pen.Thickness, this.AdornedElement.RenderSize.Height ); - break; - case DropMarkOrientation.Horizontal: - size = new Size( this.AdornedElement.RenderSize.Width, m_pen.Thickness ); - break; - } + return ( this.Parent as AdornerLayer ); } - - return size; } - public override GeneralTransform GetDesiredTransform( GeneralTransform transform ) + #endregion + + protected override void OnRender( DrawingContext drawingContext ) { - double offsetX = this.HorizontalPosition; - double offsetY = 0d; + base.OnRender( drawingContext ); - if( m_pen != null ) + if( !m_render || ( m_pen == null ) ) + return; + + var renderSize = this.AdornedElement.RenderSize; + + Point startPoint = new Point( this.HorizontalPosition, 0d ); + Point endPoint; + + switch( m_orientation ) { - switch( m_orientation ) - { - case DropMarkOrientation.Default: - case DropMarkOrientation.Vertical: - offsetX -= m_pen.Thickness / 2; - break; - case DropMarkOrientation.Horizontal: - offsetY -= m_pen.Thickness / 2; - break; - } - - if( m_alignment == DropMarkAlignment.Far ) - { - if( m_orientation == DropMarkOrientation.Vertical ) + case DropMarkOrientation.Default: + case DropMarkOrientation.Vertical: { - // A "far" vertical drop mark is displayed at the right - offsetX += this.AdornedElement.RenderSize.Width; + if( m_alignment == DropMarkAlignment.Far ) + { + startPoint.X += renderSize.Width; + } + + endPoint = new Point( startPoint.X, renderSize.Height ); } - else + break; + case DropMarkOrientation.Horizontal: { - // A "far" horizontal drop mark is displayed at the bottom - offsetY += this.AdornedElement.RenderSize.Height; + if( m_alignment == DropMarkAlignment.Far ) + { + startPoint.Y += renderSize.Height; + } + + endPoint = new Point( renderSize.Width, startPoint.Y ); } - } + break; + default: + return; } - GeneralTransformGroup transformGroup = new GeneralTransformGroup(); + drawingContext.DrawLine( m_pen, startPoint, endPoint ); + } - transformGroup.Children.Add( base.GetDesiredTransform( transform ) ); - transformGroup.Children.Add( new TranslateTransform( offsetX, offsetY ) ); + internal void UpdateAlignment( RelativePoint mousePosition ) + { + var relativePosition = mousePosition.GetPoint( this.AdornedElement ); + var elementSize = this.AdornedElement.RenderSize; - return transformGroup; + if( m_orientation == DropMarkOrientation.Horizontal ) + { + this.Alignment = ( relativePosition.Y < elementSize.Height / 2d ) ? DropMarkAlignment.Near : DropMarkAlignment.Far; + } + else + { + this.Alignment = ( relativePosition.X < elementSize.Width / 2d ) ? DropMarkAlignment.Near : DropMarkAlignment.Far; + } } - protected override void OnRender( DrawingContext drawingContext ) + private void Update() { - if( m_pen != null ) - { - Size renderSize = this.RenderSize; - Point startPoint = new Point(); - Point endPoint = new Point(); - - switch( m_orientation ) - { - case DropMarkOrientation.Default: - case DropMarkOrientation.Vertical: - startPoint = new Point( renderSize.Width / 2, 0d ); - endPoint = new Point( startPoint.X, renderSize.Height ); - break; - case DropMarkOrientation.Horizontal: - startPoint = new Point( 0d, renderSize.Height / 2 ); - endPoint = new Point( renderSize.Width, startPoint.Y ); - break; - } + if( !m_render ) + return; - drawingContext.DrawLine( m_pen, startPoint, endPoint ); - } + if( !this.InvalidateAdornerLayer() ) + return; - base.OnRender( drawingContext ); + m_render = false; + this.LayoutUpdated += new EventHandler( this.OnLayoutUpdated ); } - private void UpdatePosition() + private bool InvalidateAdornerLayer() { - AdornerLayer adornerLayer = this.Parent as AdornerLayer; + var adornerLayer = this.AdornerLayer; + if( adornerLayer == null ) + return false; - if( adornerLayer != null ) - { - adornerLayer.Update( this.AdornedElement ); - } + adornerLayer.Update( this.AdornedElement ); + return true; } - private DropMarkAlignment m_alignment = DropMarkAlignment.ExplicitPosition; - private Pen m_pen; - private DropMarkOrientation m_orientation; + private void OnLayoutUpdated( object sender, EventArgs e ) + { + m_render = true; + + this.LayoutUpdated -= new EventHandler( this.OnLayoutUpdated ); + this.InvalidateVisual(); + this.InvalidateAdornerLayer(); + } + + private readonly DropMarkOrientation m_orientation; + private readonly Pen m_pen; + private bool m_render; } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/(Clipboard)/CF_HtmlStream.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/(Clipboard)/CF_HtmlStream.cs new file mode 100644 index 00000000..13a6e738 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/(Clipboard)/CF_HtmlStream.cs @@ -0,0 +1,201 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Diagnostics; +using System.Globalization; + +namespace Xceed.Wpf.DataGrid.Export +{ + // Class used to format data into the CF_HTML Clipbard Format + // http://msdn.microsoft.com/en-us/library/aa767917(VS.85).aspx + internal sealed class CF_HtmlStream : Stream + { + public CF_HtmlStream( Stream innerStream ) + { + if( innerStream == null ) + throw new ArgumentNullException( "innerStream" ); + + if( innerStream.CanWrite == false ) + throw new InvalidOperationException( "An attempt was made to use a non-writable stream." ); + + if( innerStream.CanSeek == false ) + throw new InvalidOperationException( "An attempt was made to use a non-seekable stream." ); + + m_innerStream = innerStream; + + StringBuilder headerStringBuilder = new StringBuilder(); + headerStringBuilder.Append( "Version:1.0" ); + headerStringBuilder.Append( Environment.NewLine ); + headerStringBuilder.Append( "StartHTML:-1" ); // This is optional according to MSDN documentation + headerStringBuilder.Append( Environment.NewLine ); + headerStringBuilder.Append( "EndHTML:-1" ); // This is optional according to MSDN documentation + headerStringBuilder.Append( Environment.NewLine ); + headerStringBuilder.Append( "StartFragment:0000000109" ); // Always 109 bytes from start of Version to the end of tag + headerStringBuilder.Append( Environment.NewLine ); + + // Get the offset of the EndFragment: tag to be able to modify the 10 digits + m_endFragmentOffset = headerStringBuilder.ToString().Length; + + Debug.Assert( m_endFragmentOffset == 65 ); + + headerStringBuilder.Append( "EndFragment:0000000000" ); // We write 0000000000 and we will update this field when the Stream is closed + headerStringBuilder.Append( Environment.NewLine ); + headerStringBuilder.Append( "" ); + + string headerString = headerStringBuilder.ToString(); + + byte[] tempBuffer = Encoding.UTF8.GetBytes( headerString ); + + m_headerBytesLength = headerStringBuilder.Length; + + Debug.Assert( m_headerBytesLength == tempBuffer.Length ); + Debug.Assert( tempBuffer.Length == 109 ); + + m_innerStream.Write( tempBuffer, 0, m_headerBytesLength ); + m_HtmlContentByteCount = 0; + } + + public override bool CanRead + { + get + { + return false; + } + } + + public override bool CanSeek + { + get + { + return false; + } + } + + public override bool CanWrite + { + get + { + return true; + } + } + + public override long Length + { + get + { + return m_headerBytesLength + m_HtmlContentByteCount + s_footerBytes.Length; + } + } + + public override long Position + { + get + { + throw new NotSupportedException(); + } + set + { + throw new NotSupportedException(); + } + } + + public override void Close() + { + // Already closed, nothing to do + if( m_closed ) + return; + + // Update the value of EndFragment field in the header + string endFragmentOffset = ( m_HtmlContentByteCount + m_headerBytesLength ).ToString( "0000000000", CultureInfo.InvariantCulture ); + + m_innerStream.Seek( m_endFragmentOffset, SeekOrigin.Begin ); + + byte[] tempBuffer = Encoding.UTF8.GetBytes( "EndFragment:" + endFragmentOffset ); + Debug.Assert( tempBuffer.Length == 22 ); + m_innerStream.Write( tempBuffer, 0, tempBuffer.Length ); + + // Append the final end line and EndFragment tag + m_innerStream.Seek( 0, SeekOrigin.End ); + m_innerStream.Write( s_footerBytes, 0, s_footerBytes.Length ); + m_innerStream.Flush(); + + m_closed = true; + } + + protected override void Dispose( bool disposing ) + { + this.Close(); + } + + public override void Flush() + { + m_innerStream.Flush(); + } + + public override int Read( byte[] buffer, int offset, int count ) + { + throw new NotSupportedException(); + } + + public override int ReadByte() + { + throw new NotSupportedException(); + } + + public override long Seek( long offset, SeekOrigin origin ) + { + throw new NotSupportedException(); + } + + public override void SetLength( long value ) + { + throw new NotSupportedException(); + } + + public override void WriteByte( byte value ) + { + this.CheckIfClosed(); + m_HtmlContentByteCount++; + m_innerStream.WriteByte( value ); + } + + public override void Write( byte[] buffer, int offset, int count ) + { + this.CheckIfClosed(); + m_HtmlContentByteCount += count; + m_innerStream.Write( buffer, offset, count ); + } + + private void CheckIfClosed() + { + if( m_closed ) + throw new InvalidOperationException( "An attempt was made to access a closed stream." ); + } + + private bool m_closed; // = false; + private int m_endFragmentOffset; // = 0; + private int m_headerBytesLength; // = 0; + private long m_HtmlContentByteCount; // = 0; + private Stream m_innerStream; // = null; + + private static byte[] s_footerBytes = Encoding.UTF8.GetBytes( Environment.NewLine + "" ); + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/(Clipboard)/ClipboardExporterBase.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/(Clipboard)/ClipboardExporterBase.cs index e34bab80..0603d1b0 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/(Clipboard)/ClipboardExporterBase.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/(Clipboard)/ClipboardExporterBase.cs @@ -15,11 +15,9 @@ ***********************************************************************************/ using System; -using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; -using System.Globalization; using System.Windows; namespace Xceed.Wpf.DataGrid.Export @@ -209,7 +207,7 @@ namespace Xceed.Wpf.DataGrid.Export this.UpdateExporterIndentation( detailLevel ); // Get master indexes that have mapped expanded details - List indexesToMasterItemList = dataGridContext.CustomItemContainerGenerator.GetMasterIndexexWithExpandedDetails(); + List indexesToMasterItemList = dataGridContext.CustomItemContainerGenerator.GetMasterIndexesWithExpandedDetails(); // Get the index of the next detail to export in case // it is expanded before the first selected index of the @@ -290,28 +288,24 @@ namespace Xceed.Wpf.DataGrid.Export } } - private void ExportDataItemCore( DataGridContext dataGridContext, ClipboardExporterBase clipboardExporter, int itemIndex, object item, int[] exportedVisiblePositions, - ColumnBase[] columnsByVisiblePosition ) + private void ExportDataItemCore( DataGridContext dataGridContext, ClipboardExporterBase clipboardExporter, int itemIndex, object item, + int[] exportedVisiblePositions, ColumnBase[] columnsByVisiblePosition ) { - DataGridCollectionViewBase dataGridCollectionViewBase = dataGridContext.ItemsSourceCollection as DataGridCollectionViewBase; + var dataGridCollectionViewBase = dataGridContext.ItemsSourceCollection as DataGridCollectionViewBase; clipboardExporter.StartDataItem( dataGridContext, item ); // Ensure the count does not exceeds the columns count - int exportedVisiblePositionsCount = exportedVisiblePositions.Length; + var exportedVisiblePositionsCount = exportedVisiblePositions.Length; exportedVisiblePositionsCount = Math.Min( exportedVisiblePositionsCount, columnsByVisiblePosition.Length ); - HashSet intersectedIndexes = this.GetIntersectedRangesForIndex( dataGridContext, itemIndex, exportedVisiblePositions, exportedVisiblePositionsCount ); - - object fieldValue = null; - Column column = null; + var intersectedIndexes = this.GetIntersectedRangesForIndex( dataGridContext, itemIndex, exportedVisiblePositions, exportedVisiblePositionsCount ); for( int i = 0; i < exportedVisiblePositionsCount; i++ ) { - // Reset field value - fieldValue = null; - - int visiblePosition = exportedVisiblePositions[ i ]; + var fieldValue = default( object ); + var column = default( Column ); + var visiblePosition = exportedVisiblePositions[ i ]; // Export null if not intersected by a SelectionRange if( intersectedIndexes.Contains( visiblePosition ) ) @@ -322,29 +316,25 @@ namespace Xceed.Wpf.DataGrid.Export if( column == null ) continue; - // Use DataGridCollectionView directly since the DataGridItemProperty uses PropertyDescriptor which increase - // the read of the field value - DataGridItemPropertyBase dataGridItemProperty = null; + // Use DataGridCollectionView directly since the DataGridItemProperty uses PropertyDescriptor which increase the read of the field value + var dataGridItemProperty = default( DataGridItemPropertyBase ); - // Try to get a DataGridItemProperty matching the column FieldName - // and get the value from it + // Try to get a DataGridItemProperty matching the column FieldName and get the value from it if( dataGridCollectionViewBase != null ) { - dataGridItemProperty = dataGridCollectionViewBase.ItemProperties[ column.FieldName ]; + dataGridItemProperty = ItemsSourceHelper.GetItemPropertyFromProperty( dataGridCollectionViewBase.ItemProperties, column.FieldName ); if( dataGridItemProperty != null ) { - fieldValue = dataGridItemProperty.GetValue( item ); + fieldValue = ItemsSourceHelper.GetValueFromItemProperty( dataGridItemProperty, item ); } } // If none was found, create a BindingPathValueExtractor from this column if( ( dataGridCollectionViewBase == null ) || ( dataGridItemProperty == null ) ) { - // We don't have a DataGridCollectionView, use a BindingPathValueExtractor - // to create a binding to help us get the value for the Column in the - // data item - BindingPathValueExtractor extractorForRead = null; + // We don't have a DataGridCollectionView, use a BindingPathValueExtractor to create a binding to help us get the value for the Column in the data item + var extractorForRead = default( BindingPathValueExtractor ); if( m_columnToBindingPathExtractor.TryGetValue( column, out extractorForRead ) == false ) { @@ -359,19 +349,27 @@ namespace Xceed.Wpf.DataGrid.Export if( fieldValue != null ) { //Verify if the value should be converted to the displayed value for exporting. - ForeignKeyConfiguration foreignKeyConfiguration = column.ForeignKeyConfiguration; - + var foreignKeyConfiguration = column.ForeignKeyConfiguration; if( foreignKeyConfiguration != null && foreignKeyConfiguration.UseDisplayedValueWhenExporting ) { fieldValue = foreignKeyConfiguration.GetDisplayMemberValue( fieldValue ); } - else if( column.DisplayedValueConverter != null ) + else { - fieldValue = column.DisplayedValueConverter.Convert( fieldValue, typeof( object ), column.DisplayedValueConverterParameter, column.GetCulture( column.DisplayedValueConverterCulture ) ); - } - else if( !string.IsNullOrEmpty( column.CellContentStringFormat ) ) - { - fieldValue = string.Format( column.GetCulture(), column.CellContentStringFormat, fieldValue ); + var valueConverter = column.DisplayedValueConverter; + if( valueConverter != null ) + { + fieldValue = valueConverter.Convert( fieldValue, typeof( object ), column.DisplayedValueConverterParameter, + column.GetCulture( column.DisplayedValueConverterCulture ) ); + } + else + { + var valueFormat = column.CellContentStringFormat; + if( !string.IsNullOrEmpty( valueFormat ) ) + { + fieldValue = string.Format( column.GetCulture(), valueFormat, fieldValue ); + } + } } } @@ -482,7 +480,6 @@ namespace Xceed.Wpf.DataGrid.Export private void ExportDataItem( DataGridContext dataGridContext, int itemIndex, object item, int detailLevel, int[] exportedVisiblePositions, ColumnBase[] columnsByVisiblePosition ) { - Debug.WriteLine( string.Format( "ExportDataItem for detail level {0}, itemIndex {1}", detailLevel, itemIndex ) ); foreach( ClipboardExporterBase clipboardExporter in m_clipboardExporters ) { @@ -503,7 +500,6 @@ namespace Xceed.Wpf.DataGrid.Export if( m_lastExportedHeaderDetailLevel == detailLevel ) return; - Debug.WriteLine( string.Format( "ExportHeaders for detail level {0}", detailLevel ) ); foreach( ClipboardExporterBase clipboardExporter in m_clipboardExporters ) { diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/(Clipboard)/HtmlClipboardExporter.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/(Clipboard)/HtmlClipboardExporter.cs new file mode 100644 index 00000000..f8529bf1 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/(Clipboard)/HtmlClipboardExporter.cs @@ -0,0 +1,217 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.ComponentModel; +using System.IO; +using System.Diagnostics; + +namespace Xceed.Wpf.DataGrid.Export +{ + public class HtmlClipboardExporter : ClipboardExporterBase + { + #region PUBLIC CONSTRUCTORS + + public HtmlClipboardExporter() + : base() + { + this.IncludeColumnHeaders = true; + this.FormatSettings = new HtmlFormatSettings(); + m_indentationString = string.Empty; + + // We keep a reference to the innerStream to return it when clipboard export is finished + m_memoryStream = new MemoryStream(); + m_baseStream = new CF_HtmlStream( m_memoryStream ); + } + + #endregion + + #region PUBLIC PROPERTIES + + public HtmlFormatSettings FormatSettings + { + get; + private set; + } + + #endregion + + #region PROTECTED OVERRIDES + + protected override object ClipboardData + { + get + { + // Return the innerStream of the CF_HtmlStream which contains the CF_HTML formatted data + return m_memoryStream; + } + } + + protected override void Indent() + { + string startDelimiter = this.FormatSettings.FieldStartDelimiter; + string endDelimiter = this.FormatSettings.FieldEndDelimiter; + + if( startDelimiter == null ) + startDelimiter = string.Empty; + + if( endDelimiter == null ) + endDelimiter = string.Empty; + + // By default, we suppose indentation as an empty field + m_indentationString += startDelimiter + endDelimiter; + } + + protected override void Unindent() + { + string startDelimiter = this.FormatSettings.FieldStartDelimiter; + string endDelimiter = this.FormatSettings.FieldEndDelimiter; + + if( startDelimiter == null ) + startDelimiter = string.Empty; + + if( endDelimiter == null ) + endDelimiter = string.Empty; + + if( m_indentationString == null ) + { + Debug.Fail( "Indentation must at least be string.empty when unindenting." ); + + // We initalize the indentation string and return + m_indentationString = string.Empty; + } + else + { + int emptyFieldLength = startDelimiter.Length + endDelimiter.Length; + int indentationLength = m_indentationString.Length; + + // If there are less characters in indentationString than in the empty field, just set indentation + // as string.empty + if( indentationLength < emptyFieldLength ) + { + m_indentationString = string.Empty; + } + else + { + m_indentationString = m_indentationString.Substring( 0, indentationLength - emptyFieldLength ); + } + } + } + + protected override void ResetExporter() + { + m_tempBuffer = null; + m_indentationString = string.Empty; + + // We must NOT close or dispose the previous MemoryStream since we pass this + // instance to the Clipboard directly and it becomes responsible of + // closing/disposing it + m_memoryStream = new MemoryStream(); + m_baseStream = new CF_HtmlStream( m_memoryStream ); + } + + protected override void StartExporter( string dataFormat ) + { + this.WriteToBaseStream( this.FormatSettings.ExporterStartDelimiter ); + } + + protected override void EndExporter( string dataFormat ) + { + this.WriteToBaseStream( this.FormatSettings.ExporterEndDelimiter ); + + // Force the header to be updated with length of HTML data and add the footer + m_baseStream.Close(); + } + + protected override void StartHeader( DataGridContext dataGridContext ) + { + this.WriteToBaseStream( this.FormatSettings.HeaderDataStartDelimiter ); + + if( string.IsNullOrEmpty( m_indentationString ) == false ) + { + this.WriteToBaseStream( m_indentationString ); + } + } + + protected override void StartHeaderField( DataGridContext dataGridContext, Column column ) + { + this.WriteToBaseStream( this.FormatSettings.HeaderFieldStartDelimiter ); + + object columnHeader = ( ( this.UseFieldNamesInHeader ) || ( column.Title == null ) ) ? column.FieldName : column.Title; + + string fieldValueString = FormatHelper.FormatHtmlFieldData( null, columnHeader, this.FormatSettings ); + + this.WriteToBaseStream( fieldValueString ); + this.WriteToBaseStream( this.FormatSettings.HeaderFieldEndDelimiter ); + } + + protected override void EndHeader( DataGridContext dataGridContext ) + { + this.WriteToBaseStream( this.FormatSettings.HeaderDataEndDelimiter ); + } + + protected override void StartDataItem( DataGridContext dataGridContext, object dataItem ) + { + this.WriteToBaseStream( this.FormatSettings.DataStartDelimiter ); + + if( string.IsNullOrEmpty( m_indentationString ) == false ) + { + this.WriteToBaseStream( m_indentationString ); + } + } + + protected override void StartDataItemField( DataGridContext dataGridContext, Column column, object fieldValue ) + { + this.WriteToBaseStream( this.FormatSettings.FieldStartDelimiter ); + string fieldValueString = FormatHelper.FormatHtmlFieldData( null, fieldValue, this.FormatSettings ); + this.WriteToBaseStream( fieldValueString ); + this.WriteToBaseStream( this.FormatSettings.FieldEndDelimiter ); + } + + protected override void EndDataItem( DataGridContext dataGridContext, object dataItem ) + { + this.WriteToBaseStream( this.FormatSettings.DataEndDelimiter ); + } + + #endregion + + #region PRIVATE METHODS + + private void WriteToBaseStream( string value ) + { + if( string.IsNullOrEmpty( value ) ) + return; + + m_tempBuffer = Encoding.UTF8.GetBytes( value ); + + m_baseStream.Write( m_tempBuffer, 0, m_tempBuffer.Length ); + } + + #endregion + + #region PRIVATE FIELDS + + private string m_indentationString; // = null; + private MemoryStream m_memoryStream; // = null; + private CF_HtmlStream m_baseStream; // = null; + private byte[] m_tempBuffer; // = null; + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/(Clipboard)/HtmlFormatSettings.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/(Clipboard)/HtmlFormatSettings.cs new file mode 100644 index 00000000..59bb495f --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/(Clipboard)/HtmlFormatSettings.cs @@ -0,0 +1,106 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Xceed.Wpf.DataGrid.Export +{ + public class HtmlFormatSettings : FormatSettingsBase + { + public HtmlFormatSettings() + { + this.ExporterStartDelimiter = ""; + this.ExporterEndDelimiter = "
"; + + this.HeaderFieldStartDelimiter = ""; + this.HeaderFieldEndDelimiter = ""; + this.HeaderDataStartDelimiter = ""; + this.HeaderDataEndDelimiter = ""; + + this.FieldStartDelimiter = ""; + this.FieldEndDelimiter = ""; + this.DataStartDelimiter = ""; + this.DataEndDelimiter = ""; + } + + #region PUBLIC PROPERTIES + + public string ExporterStartDelimiter + { + get; + set; + } + + public string ExporterEndDelimiter + { + get; + set; + } + + public string HeaderFieldStartDelimiter + { + get; + set; + } + + public string HeaderFieldEndDelimiter + { + get; + set; + } + + public string HeaderDataStartDelimiter + { + get; + set; + } + + public string HeaderDataEndDelimiter + { + get; + set; + } + + public string FieldStartDelimiter + { + get; + set; + } + + public string FieldEndDelimiter + { + get; + set; + } + + public string DataStartDelimiter + { + get; + set; + } + + public string DataEndDelimiter + { + get; + set; + } + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/(Clipboard)/UnicodeCsvClipboardExporter.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/(Clipboard)/UnicodeCsvClipboardExporter.cs new file mode 100644 index 00000000..534d6db8 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/(Clipboard)/UnicodeCsvClipboardExporter.cs @@ -0,0 +1,338 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 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 + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text; + +namespace Xceed.Wpf.DataGrid.Export +{ + public class UnicodeCsvClipboardExporter : ClipboardExporterBase + { + public UnicodeCsvClipboardExporter() + { + this.IncludeColumnHeaders = true; + this.FormatSettings = new CsvFormatSettings(); + m_indentationString = string.Empty; + m_baseStream = new ToStringMemoryStream(); + } + + #region PUBLIC PROPERTIES + + public CsvFormatSettings FormatSettings + { + get; + private set; + } + + #endregion + + #region PROTECTED OVERRIDES + + protected override object ClipboardData + { + get + { + return m_baseStream; + } + } + + protected override void Indent() + { + char separator = this.FormatSettings.Separator; + m_indentationString += separator; + } + + protected override void Unindent() + { + char separator = this.FormatSettings.Separator; + + if( m_indentationString == null ) + { + Debug.Fail( "Indentation must at least be string.empty when unindenting." ); + m_indentationString = string.Empty; + } + else + { + int separatorLength = 1; + int indentationLength = m_indentationString.Length; + + // If there are less characters in indentationString than in the empty field, just set indentation + // as string.empty + if( indentationLength < separatorLength ) + { + m_indentationString = string.Empty; + } + else + { + m_indentationString = m_indentationString.Substring( 0, indentationLength - separatorLength ); + } + } + } + + protected override void ResetExporter() + { + m_baseStream = new ToStringMemoryStream(); + m_indentationString = string.Empty; + } + + protected override void StartHeader( DataGridContext dataGridContext ) + { + if( string.IsNullOrEmpty( m_indentationString ) == false ) + this.WriteToBaseStream( m_indentationString ); + + // The next StartDataItemField will be considered as first column + m_isFirstColumn = true; + } + + protected override void StartHeaderField( DataGridContext dataGridContext, Column column ) + { + // We always insert the separator before the value except for the first item + if( !m_isFirstColumn ) + { + this.WriteToBaseStream( this.FormatSettings.Separator ); + } + else + { + m_isFirstColumn = false; + } + + object columnHeader = ( ( this.UseFieldNamesInHeader ) || ( column.Title == null ) ) ? column.FieldName : column.Title; + string fieldValueString = UnicodeCsvClipboardExporter.FormatCsvData( null, columnHeader, this.FormatSettings ); + + this.WriteToBaseStream( fieldValueString ); + } + + protected override void EndHeader( DataGridContext dataGridContext ) + { + this.WriteToBaseStream( this.FormatSettings.NewLine ); + } + + protected override void StartDataItem( DataGridContext dataGridContext, object dataItem ) + { + if( string.IsNullOrEmpty( m_indentationString ) == false ) + this.WriteToBaseStream( m_indentationString ); + + // The next StartDataItemField will be considered as first column + m_isFirstColumn = true; + } + + protected override void StartDataItemField( DataGridContext dataGridContext, Column column, object fieldValue ) + { + // We always insert the separator before the value except for the first item + if( !m_isFirstColumn ) + { + this.WriteToBaseStream( this.FormatSettings.Separator ); + } + else + { + m_isFirstColumn = false; + } + + string fieldValueString = UnicodeCsvClipboardExporter.FormatCsvData( null, fieldValue, this.FormatSettings ); + + this.WriteToBaseStream( fieldValueString ); + } + + protected override void EndDataItem( DataGridContext dataGridContext, object dataItem ) + { + this.WriteToBaseStream( this.FormatSettings.NewLine ); + } + + #endregion + + #region PRIVATE METHODS + + private void WriteToBaseStream( char value ) + { + byte[] tempBuffer = Encoding.Unicode.GetBytes( new char[] { value } ); + m_baseStream.Write( tempBuffer, 0, tempBuffer.Length ); + } + + private void WriteToBaseStream( string value ) + { + if( string.IsNullOrEmpty( value ) ) + return; + + byte[] tempBuffer = Encoding.Unicode.GetBytes( value ); + m_baseStream.Write( tempBuffer, 0, tempBuffer.Length ); + } + + #endregion + + #region Private Static Methods + + private static string FormatCsvData( Type dataType, object dataValue, CsvFormatSettings formatSettings ) + { + string outputString = null; + bool checkWhitespace = true; + + if( ( dataValue != null ) && ( !Convert.IsDBNull( dataValue ) ) && ( !( dataValue is Array ) ) ) + { + if( dataType == null ) + dataType = dataValue.GetType(); + + if( dataType == typeof( string ) ) + { + if( formatSettings.TextQualifier == '\0' ) + { + outputString = ( string )dataValue; + } + else + { + outputString = formatSettings.TextQualifier + ( string )dataValue + formatSettings.TextQualifier; + } + + checkWhitespace = false; + } + else if( dataType == typeof( DateTime ) ) + { + if( !string.IsNullOrEmpty( formatSettings.DateTimeFormat ) ) + { + if( formatSettings.Culture == null ) + { + outputString = ( ( DateTime )dataValue ).ToString( formatSettings.DateTimeFormat, CultureInfo.InvariantCulture ); + } + else + { + outputString = ( ( DateTime )dataValue ).ToString( formatSettings.DateTimeFormat, formatSettings.Culture ); + } + } + } + else if( ( dataType == typeof( double ) ) || + ( dataType == typeof( decimal ) ) || + ( dataType == typeof( float ) ) || + ( dataType == typeof( int ) ) || + ( dataType == typeof( double ) ) || + ( dataType == typeof( decimal ) ) || + ( dataType == typeof( float ) ) || + ( dataType == typeof( short ) ) || + ( dataType == typeof( Single ) ) || + ( dataType == typeof( UInt16 ) ) || + ( dataType == typeof( UInt32 ) ) || + ( dataType == typeof( UInt64 ) ) || + ( dataType == typeof( Int16 ) ) || + ( dataType == typeof( Int64 ) ) ) + { + string format = formatSettings.NumericFormat; + + if( ( ( dataType == typeof( double ) ) || + ( dataType == typeof( decimal ) ) || + ( dataType == typeof( float ) ) ) && + ( !string.IsNullOrEmpty( formatSettings.FloatingPointFormat ) ) ) + format = formatSettings.FloatingPointFormat; + + if( !string.IsNullOrEmpty( format ) ) + { + if( formatSettings.Culture == null ) + { + outputString = string.Format( CultureInfo.InvariantCulture, "{0:" + format + "}", dataValue ); + } + else + { + outputString = string.Format( formatSettings.Culture, "{0:" + format + "}", dataValue ); + } + } + } + + if( outputString == null ) + { + if( formatSettings.Culture == null ) + { + outputString = string.Format( CultureInfo.InvariantCulture, "{0}", dataValue ); + } + else + { + outputString = string.Format( formatSettings.Culture, "{0}", dataValue ); + } + } + + // For dates and numbers, as a rule, we never use the TextQualifier. However, the + // specified format can introduce whitespaces. To better support this case, we add + // the TextQualifier if needed. + if( ( checkWhitespace ) && ( formatSettings.TextQualifier != '\0' ) ) + { + bool useTextQualifier = false; + + // If the output string contains the character used to separate the fields, we + // don't bother checking for whitespace. TextQualifier will be used. + if( outputString.IndexOf( formatSettings.Separator ) < 0 ) + { + for( int i = 0; i < outputString.Length; i++ ) + { + if( char.IsWhiteSpace( outputString, i ) ) + { + useTextQualifier = true; + break; + } + } + } + else + { + useTextQualifier = true; + } + + if( useTextQualifier ) + outputString = formatSettings.TextQualifier + outputString + formatSettings.TextQualifier; + } + } + + return outputString; + } + + #endregion + + #region PRIVATE FIELDS + + private string m_indentationString; // = null; + private MemoryStream m_baseStream; // = null; + private bool m_isFirstColumn; // = false; + + #endregion + + #region ToStringMemoryStream Private Class + + // This class is used to force the ToString of the + // MemoryStream to return the content of the Stream + // instead of the name of the Type. + private class ToStringMemoryStream : MemoryStream + { + public override string ToString() + { + if( this.Length == 0 ) + { + return string.Empty; + } + else + { + try + { + return Encoding.Unicode.GetString( this.ToArray() ); + } + catch( Exception ) + { + return base.ToString(); + } + } + } + } + + #endregion + } +} + diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/FormatHelper.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/FormatHelper.cs index 65ee071e..a8cfe398 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/FormatHelper.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Export/FormatHelper.cs @@ -147,6 +147,120 @@ namespace Xceed.Wpf.DataGrid.Export return outputString; } + public static string FormatHtmlFieldData( Type dataType, object dataValue, HtmlFormatSettings formatSettings ) + { + string outputString = null; + + if( ( dataValue != null ) && ( !Convert.IsDBNull( dataValue ) ) && ( !( dataValue is Array ) ) ) + { + if( dataType == null ) + dataType = dataValue.GetType(); + + if( dataType == typeof( string ) ) + { + outputString = ( string )dataValue; + } + else if( dataType == typeof( DateTime ) ) + { + if( !string.IsNullOrEmpty( formatSettings.DateTimeFormat ) ) + { + if( formatSettings.Culture == null ) + { + outputString = ( ( DateTime )dataValue ).ToString( formatSettings.DateTimeFormat, CultureInfo.InvariantCulture ); + } + else + { + outputString = ( ( DateTime )dataValue ).ToString( formatSettings.DateTimeFormat, formatSettings.Culture ); + } + } + } + else if( ( dataType == typeof( double ) ) || + ( dataType == typeof( decimal ) ) || + ( dataType == typeof( float ) ) || + ( dataType == typeof( int ) ) || + ( dataType == typeof( double ) ) || + ( dataType == typeof( decimal ) ) || + ( dataType == typeof( float ) ) || + ( dataType == typeof( short ) ) || + ( dataType == typeof( Single ) ) || + ( dataType == typeof( UInt16 ) ) || + ( dataType == typeof( UInt32 ) ) || + ( dataType == typeof( UInt64 ) ) || + ( dataType == typeof( Int16 ) ) || + ( dataType == typeof( Int64 ) ) ) + { + string format = formatSettings.NumericFormat; + + if( ( ( dataType == typeof( double ) ) || + ( dataType == typeof( decimal ) ) || + ( dataType == typeof( float ) ) ) && + ( !string.IsNullOrEmpty( formatSettings.FloatingPointFormat ) ) ) + format = formatSettings.FloatingPointFormat; + + if( !string.IsNullOrEmpty( format ) ) + { + if( formatSettings.Culture == null ) + { + outputString = string.Format( CultureInfo.InvariantCulture, "{0:" + format + "}", dataValue ); + } + else + { + outputString = string.Format( formatSettings.Culture, "{0:" + format + "}", dataValue ); + } + } + } + + if( outputString == null ) + { + if( formatSettings.Culture == null ) + { + outputString = string.Format( CultureInfo.InvariantCulture, "{0}", dataValue ); + } + else + { + outputString = string.Format( formatSettings.Culture, "{0}", dataValue ); + } + } + } + + return FormatHelper.FormatPlainTextAsHtml( outputString ); + } + + public static void FormatHtmlData( StringBuilder htmlDataStringBuilder ) + { + string htmlDataString = htmlDataStringBuilder.ToString(); + + StringBuilder headerStringBuilder = new StringBuilder(); + headerStringBuilder.Append( "Version:1.0" ); + headerStringBuilder.Append( Environment.NewLine ); + headerStringBuilder.Append( "StartHTML:-1" ); // This is optional according to MSDN documentation + headerStringBuilder.Append( Environment.NewLine ); + headerStringBuilder.Append( "EndHTML:-1" ); // This is optional according to MSDN documentation + headerStringBuilder.Append( Environment.NewLine ); + headerStringBuilder.Append( "StartFragment:0000000109" ); // Always 109 bytes from start of Version to the end of tag + headerStringBuilder.Append( Environment.NewLine ); + headerStringBuilder.Append( "EndFragment:{0}" ); // need + 7 to "emulate" the 10 digits ( "{x}" is already 3 of the 10 chars ) + headerStringBuilder.Append( Environment.NewLine ); + headerStringBuilder.Append( "" ); + + // We assure the StartFramgment offset is correct + string headerString = headerStringBuilder.ToString(); + int startFragmentByteCounts = headerString.Length + 7; // +7 chars as mentionned above + Debug.Assert( startFragmentByteCounts == 109 ); + + // Compute the EndFragment offset => header size + html data size + final end line (after data) length (\r\n) + int endFragmentByteCounts = startFragmentByteCounts + htmlDataString.Length + Environment.NewLine.Length; + string endFragmentOffset = endFragmentByteCounts.ToString( "0000000000", CultureInfo.InvariantCulture ); + headerString = string.Format( CultureInfo.InvariantCulture, headerString, endFragmentOffset ); + + // Insert header at the beginning of the htmlDataStringBuilder + htmlDataStringBuilder.Insert( 0, headerString ); + + // Append the final end line and EndFragment tag + htmlDataStringBuilder.Append( Environment.NewLine ); + htmlDataStringBuilder.Append( "" ); + } + public static string FormatPlainTextAsHtml( string plainText ) { StringBuilder htmlStringBuilder = new StringBuilder(); @@ -166,7 +280,7 @@ namespace Xceed.Wpf.DataGrid.Export case '\r': break; - case ' ': + case '\u00A0': htmlStringBuilder.Append( " " ); break; diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FieldNameMap.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FieldNameMap.cs deleted file mode 100644 index 8e6109ab..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FieldNameMap.cs +++ /dev/null @@ -1,77 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System.ComponentModel; - -namespace Xceed.Wpf.DataGrid -{ - internal class FieldNameMap - { - public bool TryGetColumnFieldName( string name, out string columnName ) - { - return this.TryGetTarget( name, out columnName ); - } - - public bool TryGetColumnFieldName( ColumnBase column, out string columnName ) - { - if( column != null ) - return this.TryGetTarget( column.FieldName, out columnName ); - - columnName = null; - - return false; - } - - public bool TryGetColumnFieldName( SortDescription sortDescription, out string columnName ) - { - return this.TryGetTarget( sortDescription.PropertyName, out columnName ); - } - - public bool TryGetItemPropertyName( string name, out string itemPropertyName ) - { - return this.TryGetSource( name, out itemPropertyName ); - } - - public bool TryGetItemPropertyName( ColumnBase column, out string itemPropertyName ) - { - if( column != null ) - return this.TryGetSource( column.FieldName, out itemPropertyName ); - - itemPropertyName = null; - - return false; - } - - public bool TryGetItemPropertyName( SortDescription sortDescription, out string itemPropertyName ) - { - return this.TryGetSource( sortDescription.PropertyName, out itemPropertyName ); - } - - protected virtual bool TryGetSource( string targetName, out string sourceName ) - { - sourceName = targetName; - - return !string.IsNullOrEmpty( targetName ); - } - - protected virtual bool TryGetTarget( string sourceName, out string targetName ) - { - targetName = sourceName; - - return !string.IsNullOrEmpty( sourceName ); - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/AndFilterCriterion.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/AndFilterCriterion.cs deleted file mode 100644 index 1e7e6c11..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/AndFilterCriterion.cs +++ /dev/null @@ -1,208 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.ComponentModel; -using System.Diagnostics; -using System.Globalization; -using System.Text; -using System.Linq.Expressions; -using System.Linq; - -namespace Xceed.Wpf.DataGrid.FilterCriteria -{ - [CriterionDescriptor( "@ AND @", FilterOperatorPrecedence.AndOperator, FilterTokenPriority.AndOperator )] - [DebuggerDisplay( "AND( {FirstFilterCriterion}, {SecondFilterCriterion} )" )] - public class AndFilterCriterion : FilterCriterion - { - public AndFilterCriterion() - { - } - - public AndFilterCriterion( FilterCriterion firstFilterCriterion, FilterCriterion secondFilterCriterion ) - { - this.FirstFilterCriterion = firstFilterCriterion; - this.SecondFilterCriterion = secondFilterCriterion; - } - - #region FirstFilterCriterion Property - - public FilterCriterion FirstFilterCriterion - { - get - { - return m_firstFilterCriterion; - } - - set - { - if( value == null ) - throw new ArgumentNullException( "FirstFilterCriterion" ); - - if( value != m_firstFilterCriterion ) - { - if( m_firstFilterCriterion != null ) - m_firstFilterCriterion.PropertyChanged -= new PropertyChangedEventHandler( FirstFilterCriterion_PropertyChanged ); - - m_firstFilterCriterion = value; - m_firstFilterCriterion.PropertyChanged += new PropertyChangedEventHandler( FirstFilterCriterion_PropertyChanged ); - this.RaisePropertyChanged( "FirstFilterCriterion" ); - } - } - } - - private void FirstFilterCriterion_PropertyChanged( object sender, PropertyChangedEventArgs e ) - { - this.RaisePropertyChanged( "FirstFilterCriterion" ); - } - - private FilterCriterion m_firstFilterCriterion; // = null; - - #endregion FirstFilterCriterion Property - - #region SecondFilterCriterion Property - - public FilterCriterion SecondFilterCriterion - { - get - { - return m_secondFilterCriterion; - } - - set - { - if( value == null ) - throw new ArgumentNullException( "SecondFilterCriterion" ); - - if( value != m_secondFilterCriterion ) - { - if( m_secondFilterCriterion != null ) - m_secondFilterCriterion.PropertyChanged -= new PropertyChangedEventHandler( SecondFilterCriterion_PropertyChanged ); - - m_secondFilterCriterion = value; - m_secondFilterCriterion.PropertyChanged += new PropertyChangedEventHandler( SecondFilterCriterion_PropertyChanged ); - this.RaisePropertyChanged( "SecondFilterCriterion" ); - } - } - } - - private void SecondFilterCriterion_PropertyChanged( object sender, PropertyChangedEventArgs e ) - { - this.RaisePropertyChanged( "SecondFilterCriterion" ); - } - - private FilterCriterion m_secondFilterCriterion; // = null; - - #endregion SecondFilterCriterion Property - - public override string ToExpression( CultureInfo culture ) - { - if( ( this.FirstFilterCriterion == null ) || ( this.SecondFilterCriterion == null ) ) - return ""; - - StringBuilder stringBuilder = new StringBuilder( this.FirstFilterCriterion.ToExpression( culture ) ); - stringBuilder.Append( " AND " ); - stringBuilder.Append( this.SecondFilterCriterion.ToExpression( culture ) ); - - return stringBuilder.ToString(); - } - - public override Expression ToLinqExpression( IQueryable queryable, ParameterExpression parameterExpression, string propertyName ) - { - if( queryable == null ) - throw new ArgumentNullException( "queryable" ); - - if( parameterExpression == null ) - throw new ArgumentNullException( "parameterExpression" ); - - if( String.IsNullOrEmpty( propertyName ) ) - { - if( propertyName == null ) - throw new ArgumentNullException( "propertyName" ); - - throw new ArgumentException( "PropertyName must not be empty.", "propertyName" ); - } - - Expression firstFilterLINQExpression = ( m_firstFilterCriterion == null ) ? null : m_firstFilterCriterion.ToLinqExpression( queryable, parameterExpression, propertyName ); - Expression secondFilterLINQExpression = ( m_secondFilterCriterion == null ) ? null : m_secondFilterCriterion.ToLinqExpression( queryable, parameterExpression, propertyName ); - - if( ( firstFilterLINQExpression != null ) && ( secondFilterLINQExpression != null ) ) - return Expression.And( firstFilterLINQExpression, secondFilterLINQExpression ); - - if( firstFilterLINQExpression != null ) - return firstFilterLINQExpression; - - // Will return null if both criterion or resulting LINQ expressions are null; - return secondFilterLINQExpression; - } - - public override bool IsMatch( object value ) - { - if( ( m_firstFilterCriterion == null ) || ( m_secondFilterCriterion == null ) ) - return false; - - return m_firstFilterCriterion.IsMatch( value ) && m_secondFilterCriterion.IsMatch( value ); - } - - public override bool Equals( object obj ) - { - if( !base.Equals( obj ) ) - return false; - - AndFilterCriterion criterion = ( AndFilterCriterion )obj; - - return object.Equals( this.FirstFilterCriterion, criterion.FirstFilterCriterion ) - && object.Equals( this.SecondFilterCriterion, criterion.SecondFilterCriterion ); - } - - public override int GetHashCode() - { - int hash = base.GetHashCode(); - - if( this.FirstFilterCriterion != null ) - hash ^= this.FirstFilterCriterion.GetHashCode(); - - if( this.SecondFilterCriterion != null ) - hash ^= this.SecondFilterCriterion.GetHashCode(); - - return hash; - } - -#if DEBUG - public override string ToString() - { - System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder( "AND( " ); - stringBuilder.Append( this.FirstFilterCriterion.ToString() ); - stringBuilder.Append( ", " ); - stringBuilder.Append( this.SecondFilterCriterion.ToString() ); - stringBuilder.Append( " )" ); - - return stringBuilder.ToString(); - } -#endif - - protected internal override void InitializeFrom( object[] parameters, Type defaultComparisonFilterCriterionType ) - { - Debug.Assert( parameters.Length == 2, "Should have been caught earlier during BuildCriterion." ); - - if( parameters.Length != 2 ) - throw new DataGridInternalException( "Missing operand for the AND operator." ); - - this.FirstFilterCriterion = FilterParser.ProduceCriterion( parameters[ 0 ], defaultComparisonFilterCriterionType ); - this.SecondFilterCriterion = FilterParser.ProduceCriterion( parameters[ 1 ], defaultComparisonFilterCriterionType ); - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/ContainsFilterCriterion.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/ContainsFilterCriterion.cs deleted file mode 100644 index dc479eea..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/ContainsFilterCriterion.cs +++ /dev/null @@ -1,99 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Diagnostics; -using System.Globalization; -using System.Linq.Expressions; -using System.Linq; - -namespace Xceed.Wpf.DataGrid.FilterCriteria -{ - [CriterionDescriptor( "", FilterOperatorPrecedence.RelationalOperator, FilterTokenPriority.RelationalOperator )] - [DebuggerDisplay( "Contains( {Value} )" )] - public class ContainsFilterCriterion : RelationalFilterCriterion - { - public ContainsFilterCriterion() - : base() - { - } - - public ContainsFilterCriterion( object value ) - : base( value ) - { - } - - public override string ToExpression( CultureInfo culture ) - { - string strValue = this.GetValueForExpression( culture ); - - return strValue ?? ""; - } - - public override Expression ToLinqExpression( IQueryable queryable, ParameterExpression parameterExpression, string propertyName ) - { - if( queryable == null ) - throw new ArgumentNullException( "queryable" ); - - if( parameterExpression == null ) - throw new ArgumentNullException( "parameterExpression" ); - - if( String.IsNullOrEmpty( propertyName ) ) - { - if( propertyName == null ) - throw new ArgumentNullException( "propertyName" ); - - throw new ArgumentException( "PropertyName must not be empty.", "propertyName" ); - } - - string queriedValue = this.Value as string; - - if( queriedValue == null ) - queriedValue = string.Empty; - - return queryable.CreateContainsExpression( parameterExpression, propertyName, queriedValue ); - } - - public override bool IsMatch( object value ) - { - if( value == null ) - return false; - - if( this.Value == null ) - return true; - - string searchedValue = this.Value.ToString().ToLower(); - - if( searchedValue.Length == 0 ) - return true; - - string strValue = value.ToString().ToLower(); - - return strValue.Contains( searchedValue ); - } - -#if DEBUG - public override string ToString() - { - System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder( "Contains( " ); - stringBuilder.Append( ( this.Value == null ) ? "" : this.Value.ToString() ); - stringBuilder.Append( " )" ); - - return stringBuilder.ToString(); - } -#endif - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/CriterionDescriptorAttribute.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/CriterionDescriptorAttribute.cs deleted file mode 100644 index e85fb828..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/CriterionDescriptorAttribute.cs +++ /dev/null @@ -1,59 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; - -namespace Xceed.Wpf.DataGrid.FilterCriteria -{ - [ AttributeUsage( AttributeTargets.Class, Inherited = true, AllowMultiple = false ) ] - internal sealed class CriterionDescriptorAttribute : Attribute - { - public CriterionDescriptorAttribute( string pattern, FilterOperatorPrecedence operatorPrecedence, FilterTokenPriority parserPriority ) - { - m_pattern = pattern; - m_operatorPrecedence = operatorPrecedence; - m_parserPriority = parserPriority; - } - - public string Pattern - { - get - { - return m_pattern; - } - } - - public FilterOperatorPrecedence OperatorPrecedence - { - get - { - return m_operatorPrecedence; - } - } - - public FilterTokenPriority ParserPriority - { - get - { - return m_parserPriority; - } - } - - private readonly string m_pattern; - private readonly FilterOperatorPrecedence m_operatorPrecedence; - private readonly FilterTokenPriority m_parserPriority; - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/DifferentThanFilterCriterion.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/DifferentThanFilterCriterion.cs deleted file mode 100644 index 02a6fafb..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/DifferentThanFilterCriterion.cs +++ /dev/null @@ -1,82 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Diagnostics; -using System.Globalization; -using System.Text; -using System.Windows; -using System.Linq; -using System.Linq.Expressions; - -namespace Xceed.Wpf.DataGrid.FilterCriteria -{ - [CriterionDescriptor( "<>@", FilterOperatorPrecedence.RelationalOperator, FilterTokenPriority.RelationalOperator )] - [DebuggerDisplay( "DifferentThan( {Value} )" )] - public class DifferentThanFilterCriterion : RelationalFilterCriterion - { - public DifferentThanFilterCriterion() - : base() - { - } - - public DifferentThanFilterCriterion( object value ) - : base( value ) - { - } - - public override string ToExpression( CultureInfo culture ) - { - string strValue = this.GetValueForExpression( culture ); - return ( strValue == null ) ? "" : "<>" + strValue; - } - - public override System.Linq.Expressions.Expression ToLinqExpression( IQueryable queryable, ParameterExpression parameterExpression, string propertyName ) - { - if( queryable == null ) - throw new ArgumentNullException( "queryable" ); - - if( parameterExpression == null ) - throw new ArgumentNullException( "parameterExpression" ); - - if( String.IsNullOrEmpty( propertyName ) ) - { - if( propertyName == null ) - throw new ArgumentNullException( "propertyName" ); - - throw new ArgumentException( "PropertyName must not be empty.", "propertyName" ); - } - - return queryable.CreateDifferentThanExpression( parameterExpression, propertyName, this.Value ); - } - - public override bool IsMatch( object value ) - { - return ( this.Compare( value ) != CompareResult.EqualsTo ); - } - -#if DEBUG - public override string ToString() - { - StringBuilder stringBuilder = new StringBuilder( "DifferentThan( " ); - stringBuilder.Append( ( this.Value == null ) ? "#NULL#" : this.Value.ToString() ); - stringBuilder.Append( " )" ); - - return stringBuilder.ToString(); - } -#endif - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/EndsWithFilterCriterion.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/EndsWithFilterCriterion.cs deleted file mode 100644 index d8675daa..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/EndsWithFilterCriterion.cs +++ /dev/null @@ -1,102 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Text; -using System.Diagnostics; -using System.Globalization; - -namespace Xceed.Wpf.DataGrid.FilterCriteria -{ - [CriterionDescriptor( "*@", FilterOperatorPrecedence.RelationalOperator, FilterTokenPriority.RelationalOperator )] - [DebuggerDisplay( "EndsWith( {Value} )" )] - public class EndsWithFilterCriterion : RelationalFilterCriterion - { - public EndsWithFilterCriterion() - : base() - { - } - - public EndsWithFilterCriterion( object value ) - : base( value ) - { - } - - public override string ToExpression( CultureInfo culture ) - { - string strValue = this.GetValueForExpression( culture ); - - return ( strValue == null ) ? "" : "*" + strValue; - } - - public override Expression ToLinqExpression( IQueryable queryable, ParameterExpression parameterExpression, string propertyName ) - { - if( queryable == null ) - throw new ArgumentNullException( "queryable" ); - - if( parameterExpression == null ) - throw new ArgumentNullException( "parameterExpression" ); - - if( String.IsNullOrEmpty( propertyName ) ) - { - if( propertyName == null ) - throw new ArgumentNullException( "propertyName" ); - - throw new ArgumentException( "PropertyName must not be empty.", "propertyName" ); - } - - string queriedValue = this.Value as string; - - if( queriedValue == null ) - queriedValue = string.Empty; - else - queriedValue = queriedValue.Remove( queriedValue.IndexOf( '*' ) ); - - return queryable.CreateEndsWithExpression( parameterExpression, propertyName, queriedValue ); - } - - public override bool IsMatch( object value ) - { - if( value == null ) - return false; - - if( this.Value == null ) - return true; - - string searchedValue = this.Value.ToString().ToLower(); - - if( searchedValue.Length == 0 ) - return true; - - string strValue = value.ToString().ToLower(); - return strValue.EndsWith( searchedValue, true, CultureInfo.CurrentCulture ); - } - -#if DEBUG - public override string ToString() - { - System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder( "EndsWith( " ); - stringBuilder.Append( ( this.Value == null ) ? "#NULL#" : this.Value.ToString() ); - stringBuilder.Append( " )" ); - - return stringBuilder.ToString(); - } -#endif - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/EqualToFilterCriterion.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/EqualToFilterCriterion.cs deleted file mode 100644 index bc109faa..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/EqualToFilterCriterion.cs +++ /dev/null @@ -1,81 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Diagnostics; -using System.Globalization; -using System.Text; -using System.Linq; -using System.Linq.Expressions; - -namespace Xceed.Wpf.DataGrid.FilterCriteria -{ - [CriterionDescriptor( "=@", FilterOperatorPrecedence.RelationalOperator, FilterTokenPriority.RelationalOperator )] - [DebuggerDisplay( "EqualTo( {Value} )" )] - public class EqualToFilterCriterion : RelationalFilterCriterion - { - public EqualToFilterCriterion() - : base() - { - } - - public EqualToFilterCriterion( object value ) - : base( value ) - { - } - - public override string ToExpression( CultureInfo culture ) - { - string strValue = this.GetValueForExpression( culture ); - return ( strValue == null ) ? "" : "=" + strValue; - } - - public override Expression ToLinqExpression( IQueryable queryable, ParameterExpression parameterExpression, string propertyName ) - { - if( queryable == null ) - throw new ArgumentNullException( "queryable" ); - - if( parameterExpression == null ) - throw new ArgumentNullException( "parameterExpression" ); - - if( String.IsNullOrEmpty( propertyName ) ) - { - if( propertyName == null ) - throw new ArgumentNullException( "propertyName" ); - - throw new ArgumentException( "PropertyName must not be empty.", "propertyName" ); - } - - return queryable.CreateEqualExpression( parameterExpression, propertyName, this.Value ); - } - - public override bool IsMatch( object value ) - { - return ( this.Compare( value ) == CompareResult.EqualsTo ); - } - -#if DEBUG - public override string ToString() - { - StringBuilder stringBuilder = new StringBuilder( "EqualTo( " ); - stringBuilder.Append( ( this.Value == null ) ? "#NULL#" : this.Value.ToString() ); - stringBuilder.Append( " )" ); - - return stringBuilder.ToString(); - } -#endif - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/FilterCriterion.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/FilterCriterion.cs deleted file mode 100644 index ceeec6cd..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/FilterCriterion.cs +++ /dev/null @@ -1,112 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.ComponentModel; -using System.Globalization; -using System.Linq.Expressions; -using System.Linq; - -namespace Xceed.Wpf.DataGrid.FilterCriteria -{ - [CriterionDescriptor( "", FilterOperatorPrecedence.Default, FilterTokenPriority.Default )] - public abstract class FilterCriterion : INotifyPropertyChanged - { -#if DEBUG - [Obsolete( "This method exists for the general public. Consider using the overload receiving the culture." )] -#endif - public static FilterCriterion Parse( string expression, Type targetDataType ) - { - return FilterCriterion.Parse( expression, targetDataType, null ); - } - - public static FilterCriterion Parse( string expression, Type targetDataType, CultureInfo culture ) - { - if( expression == null ) - throw new ArgumentNullException( "expression" ); - - if( targetDataType == null ) - throw new ArgumentNullException( "targetDataType" ); - - return FilterParser.Parse( expression, targetDataType, culture ); - } - -#if DEBUG - [Obsolete( "This method exists for the general public. Consider using the overload receiving the culture." )] -#endif - public static bool TryParse( string expression, Type targetDataType, out FilterCriterion filterCriterion ) - { - return FilterCriterion.TryParse( expression, targetDataType, null, out filterCriterion ); - } - - public static bool TryParse( string expression, Type targetDataType, CultureInfo culture, out FilterCriterion filterCriterion ) - { - if( expression == null ) - throw new ArgumentNullException( "expression" ); - - if( targetDataType == null ) - throw new ArgumentNullException( "targetDataType" ); - - filterCriterion = FilterParser.TryParse( expression, targetDataType, culture ); - - return ( filterCriterion != null ) || ( FilterParser.LastError.Length == 0 ); - } - - public abstract bool IsMatch( object value ); - - public abstract string ToExpression( CultureInfo culture ); - - public abstract Expression ToLinqExpression( IQueryable queryable, ParameterExpression parameterExpression, string propertyName ); - - public override bool Equals( object obj ) - { - FilterCriterion filterCriterion = obj as FilterCriterion; - - if( filterCriterion == null ) - return false; - - return this.GetType() == filterCriterion.GetType(); - } - - public override int GetHashCode() - { - return this.GetType().GetHashCode(); - } - -#if DEBUG - public override string ToString() - { - return "#" + this.GetType().Name + "#"; - } -#endif - - protected internal abstract void InitializeFrom( object[] parameters, Type defaultComparisonFilterCriterionType ); - - #region INotifyPropertyChanged Implementation - - public event PropertyChangedEventHandler PropertyChanged; - - protected void RaisePropertyChanged( string name ) - { - if( this.PropertyChanged != null ) - { - this.PropertyChanged( this, new PropertyChangedEventArgs( name ) ); - } - } - - #endregion - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/FilterExpressionHelper.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/FilterExpressionHelper.cs deleted file mode 100644 index ca593616..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/FilterExpressionHelper.cs +++ /dev/null @@ -1,108 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; - -namespace Xceed.Wpf.DataGrid.FilterCriteria -{ - internal class FilterExpressionHelper - { - #region LastValue Property - - internal static long LastValue - { - get; - set; - } - - #endregion - - #region IsConsecutive Property - - internal static bool IsConsecutive - { - get; - set; - } - - #endregion - - #region GreaterThanAdded Property - - internal static bool GreaterThanAdded - { - get; - set; - } - - #endregion - - internal static string BuildExpressionFromIntValue( string expression, long currentValue ) - { - //If we have an int value, let's try to find ranges of values, in oreder to build a more efficent expression than having all values separated by an OR criterion. - if( currentValue - 1 < FilterExpressionHelper.LastValue ) - { - expression = currentValue.ToString(); - } - else if( currentValue - 1 > FilterExpressionHelper.LastValue ) - { - if( FilterExpressionHelper.IsConsecutive ) - { - expression += " AND <" + ( FilterExpressionHelper.LastValue + 1 ).ToString() + " OR " + currentValue.ToString(); - FilterExpressionHelper.IsConsecutive = false; - } - else - { - expression += " OR " + currentValue.ToString(); - } - FilterExpressionHelper.GreaterThanAdded = false; - } - else if( currentValue - 1 == FilterExpressionHelper.LastValue ) - { - if( !FilterExpressionHelper.GreaterThanAdded ) - { - expression = expression.Remove( expression.IndexOf( FilterExpressionHelper.LastValue.ToString() ) ); - expression += ">" + ( FilterExpressionHelper.LastValue - 1 ).ToString(); - FilterExpressionHelper.GreaterThanAdded = true; - } - FilterExpressionHelper.IsConsecutive = true; - } - - FilterExpressionHelper.LastValue = currentValue; - - return expression; - } - - internal static bool GetIsIntValuePathType( Type valuePathDataType ) - { - return valuePathDataType == typeof( sbyte ) || - valuePathDataType == typeof( byte ) || - valuePathDataType == typeof( short ) || - valuePathDataType == typeof( ushort ) || - valuePathDataType == typeof( int ) || - valuePathDataType == typeof( uint ) || - valuePathDataType == typeof( long ) || - valuePathDataType == typeof( ulong ); - } - } - - internal class EmptyCriterionObject - { - internal EmptyCriterionObject() - { - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/GreaterThanFilterCriterion.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/GreaterThanFilterCriterion.cs deleted file mode 100644 index 7d7530e8..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/GreaterThanFilterCriterion.cs +++ /dev/null @@ -1,80 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Diagnostics; -using System.Globalization; -using System.Text; -using System.Linq.Expressions; - -namespace Xceed.Wpf.DataGrid.FilterCriteria -{ - [CriterionDescriptor( ">@", FilterOperatorPrecedence.RelationalOperator, FilterTokenPriority.RelationalOperator )] - [DebuggerDisplay( "GreaterThan( {Value} )" )] - public class GreaterThanFilterCriterion : RelationalFilterCriterion - { - public GreaterThanFilterCriterion() - : base() - { - } - - public GreaterThanFilterCriterion( object value ) - : base( value ) - { - } - - public override string ToExpression( CultureInfo culture ) - { - string strValue = this.GetValueForExpression( culture ); - return ( strValue == null ) ? "" : ">" + strValue; - } - - public override System.Linq.Expressions.Expression ToLinqExpression( System.Linq.IQueryable queryable, ParameterExpression parameterExpression, string propertyName ) - { - if( queryable == null ) - throw new ArgumentNullException( "queryable" ); - - if( parameterExpression == null ) - throw new ArgumentNullException( "parameterExpression" ); - - if( String.IsNullOrEmpty( propertyName ) ) - { - if( propertyName == null ) - throw new ArgumentNullException( "propertyName" ); - - throw new ArgumentException( "PropertyName must not be empty.", "propertyName" ); - } - - return queryable.CreateGreaterThanExpression( parameterExpression, propertyName, this.Value ); - } - - public override bool IsMatch( object value ) - { - return ( this.Compare( value ) == CompareResult.GreaterThan ); - } - -#if DEBUG - public override string ToString() - { - StringBuilder stringBuilder = new StringBuilder( "GreaterThan( " ); - stringBuilder.Append( ( this.Value == null ) ? "#NULL#" : this.Value.ToString() ); - stringBuilder.Append( " )" ); - - return stringBuilder.ToString(); - } -#endif - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/GreaterThanOrEqualToFilterCriterion.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/GreaterThanOrEqualToFilterCriterion.cs deleted file mode 100644 index db1b70a6..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/GreaterThanOrEqualToFilterCriterion.cs +++ /dev/null @@ -1,81 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Diagnostics; -using System.Globalization; -using System.Text; -using System.Linq.Expressions; - -namespace Xceed.Wpf.DataGrid.FilterCriteria -{ - [CriterionDescriptor( ">=@", FilterOperatorPrecedence.RelationalOperator, FilterTokenPriority.RelationalOperator )] - [DebuggerDisplay( "GreaterThanOrEqualTo( {Value} )" )] - public class GreaterThanOrEqualToFilterCriterion : RelationalFilterCriterion - { - public GreaterThanOrEqualToFilterCriterion() - : base() - { - } - - public GreaterThanOrEqualToFilterCriterion( object value ) - : base( value ) - { - } - - public override string ToExpression( CultureInfo culture ) - { - string strValue = this.GetValueForExpression( culture ); - return ( strValue == null ) ? "" : ">=" + strValue; - } - - public override System.Linq.Expressions.Expression ToLinqExpression( System.Linq.IQueryable queryable, ParameterExpression parameterExpression, string propertyName ) - { - if( queryable == null ) - throw new ArgumentNullException( "queryable" ); - - if( parameterExpression == null ) - throw new ArgumentNullException( "parameterExpression" ); - - if( String.IsNullOrEmpty( propertyName ) ) - { - if( propertyName == null ) - throw new ArgumentNullException( "propertyName" ); - - throw new ArgumentException( "PropertyName must not be empty.", "propertyName" ); - } - - return queryable.CreateGreaterThanOrEqualExpression( parameterExpression, propertyName, this.Value ); - } - - public override bool IsMatch( object value ) - { - CompareResult result = this.Compare( value ); - return ( result == CompareResult.EqualsTo ) || ( result == CompareResult.GreaterThan ); - } - -#if DEBUG - public override string ToString() - { - StringBuilder stringBuilder = new StringBuilder( "GreaterThanOrEqualTo( " ); - stringBuilder.Append( ( this.Value == null ) ? "#NULL#" : this.Value.ToString() ); - stringBuilder.Append( " )" ); - - return stringBuilder.ToString(); - } -#endif - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/LessThanFilterCriterion.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/LessThanFilterCriterion.cs deleted file mode 100644 index 3888f67f..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/LessThanFilterCriterion.cs +++ /dev/null @@ -1,80 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Diagnostics; -using System.Globalization; -using System.Text; -using System.Linq.Expressions; - -namespace Xceed.Wpf.DataGrid.FilterCriteria -{ - [CriterionDescriptor( "<@", FilterOperatorPrecedence.RelationalOperator, FilterTokenPriority.RelationalOperator )] - [DebuggerDisplay( "LessThan( {Value} )" )] - public class LessThanFilterCriterion : RelationalFilterCriterion - { - public LessThanFilterCriterion() - : base() - { - } - - public LessThanFilterCriterion( object value ) - : base( value ) - { - } - - public override string ToExpression( CultureInfo culture ) - { - string strValue = this.GetValueForExpression( culture ); - return ( strValue == null ) ? "" : "<" + strValue; - } - - public override System.Linq.Expressions.Expression ToLinqExpression( System.Linq.IQueryable queryable, ParameterExpression parameterExpression, string propertyName ) - { - if( queryable == null ) - throw new ArgumentNullException( "queryable" ); - - if( parameterExpression == null ) - throw new ArgumentNullException( "parameterExpression" ); - - if( String.IsNullOrEmpty( propertyName ) ) - { - if( propertyName == null ) - throw new ArgumentNullException( "propertyName" ); - - throw new ArgumentException( "PropertyName must not be empty.", "propertyName" ); - } - - return queryable.CreateLesserThanExpression( parameterExpression, propertyName, this.Value ); - } - - public override bool IsMatch( object value ) - { - return ( this.Compare( value ) == CompareResult.LessThan ); - } - -#if DEBUG - public override string ToString() - { - StringBuilder stringBuilder = new StringBuilder( "LessThan( " ); - stringBuilder.Append( ( this.Value == null ) ? "#NULL#" : this.Value.ToString() ); - stringBuilder.Append( " )" ); - - return stringBuilder.ToString(); - } -#endif - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/LessThanOrEqualToFilterCriterion.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/LessThanOrEqualToFilterCriterion.cs deleted file mode 100644 index 62e26ddd..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/LessThanOrEqualToFilterCriterion.cs +++ /dev/null @@ -1,81 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Diagnostics; -using System.Globalization; -using System.Text; -using System.Linq.Expressions; - -namespace Xceed.Wpf.DataGrid.FilterCriteria -{ - [CriterionDescriptor( "<=@", FilterOperatorPrecedence.RelationalOperator, FilterTokenPriority.RelationalOperator )] - [DebuggerDisplay( "LessThanOrEqualTo( {Value} )" )] - public class LessThanOrEqualToFilterCriterion : RelationalFilterCriterion - { - public LessThanOrEqualToFilterCriterion() - : base() - { - } - - public LessThanOrEqualToFilterCriterion( object value ) - : base( value ) - { - } - - public override string ToExpression( CultureInfo culture ) - { - string strValue = this.GetValueForExpression( culture ); - return ( strValue == null ) ? "" : "<=" + strValue; - } - - public override System.Linq.Expressions.Expression ToLinqExpression( System.Linq.IQueryable queryable, ParameterExpression parameterExpression, string propertyName ) - { - if( queryable == null ) - throw new ArgumentNullException( "queryable" ); - - if( parameterExpression == null ) - throw new ArgumentNullException( "parameterExpression" ); - - if( String.IsNullOrEmpty( propertyName ) ) - { - if( propertyName == null ) - throw new ArgumentNullException( "propertyName" ); - - throw new ArgumentException( "PropertyName must not be empty.", "propertyName" ); - } - - return queryable.CreateLesserThanOrEqualExpression( parameterExpression, propertyName, this.Value ); - } - - public override bool IsMatch( object value ) - { - CompareResult result = this.Compare( value ); - return ( result == CompareResult.EqualsTo ) || ( result == CompareResult.LessThan ); - } - -#if DEBUG - public override string ToString() - { - StringBuilder stringBuilder = new StringBuilder( "LessThanOrEqualTo( " ); - stringBuilder.Append( ( this.Value == null ) ? "#NULL#" : this.Value.ToString() ); - stringBuilder.Append( " )" ); - - return stringBuilder.ToString(); - } -#endif - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/NotFilterCriterion.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/NotFilterCriterion.cs deleted file mode 100644 index 74836636..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/NotFilterCriterion.cs +++ /dev/null @@ -1,157 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.ComponentModel; -using System.Diagnostics; -using System.Globalization; -using System.Windows.Markup; -using System.Linq.Expressions; - -namespace Xceed.Wpf.DataGrid.FilterCriteria -{ - [ContentProperty( "FilterCriterion" )] - [CriterionDescriptor( "NOT @", FilterOperatorPrecedence.NotOperator, FilterTokenPriority.NotOperator )] - [DebuggerDisplay( "NOT( {FilterCriterion} )" )] - public class NotFilterCriterion : FilterCriterion - { - public NotFilterCriterion() - { - } - - public NotFilterCriterion( FilterCriterion filterCriterion ) - { - this.FilterCriterion = filterCriterion; - } - - #region FilterCriterion Property - - public FilterCriterion FilterCriterion - { - get - { - return m_filterCriterion; - } - - set - { - if( value == null ) - throw new ArgumentNullException( "FilterCriterion" ); - - if( value != m_filterCriterion ) - { - if( m_filterCriterion != null ) - m_filterCriterion.PropertyChanged -= new PropertyChangedEventHandler( FilterCriterion_PropertyChanged ); - - m_filterCriterion = value; - m_filterCriterion.PropertyChanged += new PropertyChangedEventHandler( FilterCriterion_PropertyChanged ); - this.RaisePropertyChanged( "FilterCriterion" ); - } - } - } - - private void FilterCriterion_PropertyChanged( object sender, PropertyChangedEventArgs e ) - { - this.RaisePropertyChanged( "FilterCriterion" ); - } - - private FilterCriterion m_filterCriterion; // = null; - - #endregion FilterCriterion Property - - public override string ToExpression( CultureInfo culture ) - { - if( this.FilterCriterion == null ) - return ""; - - return "NOT " + this.FilterCriterion.ToExpression( culture ); - } - - public override System.Linq.Expressions.Expression ToLinqExpression( System.Linq.IQueryable queryable, ParameterExpression parameterExpression, string propertyName ) - { - if( queryable == null ) - throw new ArgumentNullException( "queryable" ); - - if( parameterExpression == null ) - throw new ArgumentNullException( "parameterExpression" ); - - if( String.IsNullOrEmpty( propertyName ) ) - { - if( propertyName == null ) - throw new ArgumentNullException( "propertyName" ); - - throw new ArgumentException( "PropertyName must not be empty.", "propertyName" ); - } - - if( m_filterCriterion == null ) - return null; - - Expression expressionToReverse = m_filterCriterion.ToLinqExpression( queryable, parameterExpression, propertyName ); - - if( expressionToReverse == null ) - return null; - - return Expression.Not( expressionToReverse ); - } - - public override bool IsMatch( object value ) - { - if( m_filterCriterion == null ) - return false; - - return !m_filterCriterion.IsMatch( value ); - } - - protected internal override void InitializeFrom( object[] parameters, Type defaultComparisonFilterCriterionType ) - { - if( parameters.Length != 1 ) - throw new DataGridException( string.Format( FilterParser.MissingRightOperandErrorText, this.GetType().Name ) ); - - this.FilterCriterion = FilterParser.ProduceCriterion( parameters[ 0 ], defaultComparisonFilterCriterionType ); - } - - public override bool Equals( object obj ) - { - if( !base.Equals( obj ) ) - return false; - - NotFilterCriterion criterion = ( NotFilterCriterion )obj; - - return object.Equals( this.FilterCriterion, criterion.FilterCriterion ); - } - - public override int GetHashCode() - { - int hash = base.GetHashCode(); - - if( this.FilterCriterion != null ) - hash ^= this.FilterCriterion.GetHashCode(); - - return hash; - } - -#if DEBUG - public override string ToString() - { - System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder( "NOT( " ); - stringBuilder.Append( ( this.FilterCriterion == null ) ? "#NULL#" : this.FilterCriterion.ToString() ); - stringBuilder.Append( " )" ); - - return stringBuilder.ToString(); - } -#endif - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/OrFilterCriterion.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/OrFilterCriterion.cs deleted file mode 100644 index 34523662..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/OrFilterCriterion.cs +++ /dev/null @@ -1,211 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.ComponentModel; -using System.Diagnostics; -using System.Globalization; -using System.Text; -using System.Windows; -using System.Linq.Expressions; - -namespace Xceed.Wpf.DataGrid.FilterCriteria -{ - [CriterionDescriptor( "@ OR @", FilterOperatorPrecedence.OrOperator, FilterTokenPriority.OrOperator )] - [DebuggerDisplay( "OR( {FirstFilterCriterion}, {SecondFilterCriterion} )" )] - public class OrFilterCriterion : FilterCriterion - { - public OrFilterCriterion() - { - } - - public OrFilterCriterion( FilterCriterion firstFilterCriterion, FilterCriterion secondFilterCriterion ) - { - this.FirstFilterCriterion = firstFilterCriterion; - this.SecondFilterCriterion = secondFilterCriterion; - } - - #region FirstFilterCriterion Property - - public FilterCriterion FirstFilterCriterion - { - get - { - return m_firstFilterCriterion; - } - - set - { - if( value == null ) - throw new ArgumentNullException( "FirstFilterCriterion" ); - - if( value != m_firstFilterCriterion ) - { - if( m_firstFilterCriterion != null ) - m_firstFilterCriterion.PropertyChanged -= new PropertyChangedEventHandler( FirstFilterCriterion_PropertyChanged ); - - m_firstFilterCriterion = value; - m_firstFilterCriterion.PropertyChanged += new PropertyChangedEventHandler( FirstFilterCriterion_PropertyChanged ); - this.RaisePropertyChanged( "FirstFilterCriterion" ); - } - } - } - - private void FirstFilterCriterion_PropertyChanged( object sender, PropertyChangedEventArgs e ) - { - this.RaisePropertyChanged( "FirstFilterCriterion" ); - } - - private FilterCriterion m_firstFilterCriterion; // = null; - - #endregion FirstFilterCriterion Property - - #region SecondFilterCriterion Property - - public FilterCriterion SecondFilterCriterion - { - get - { - return m_secondFilterCriterion; - } - - set - { - if( value == null ) - throw new ArgumentNullException( "SecondFilterCriterion" ); - - if( value != m_secondFilterCriterion ) - { - if( m_secondFilterCriterion != null ) - m_secondFilterCriterion.PropertyChanged -= new PropertyChangedEventHandler( SecondFilterCriterion_PropertyChanged ); - - m_secondFilterCriterion = value; - m_secondFilterCriterion.PropertyChanged += new PropertyChangedEventHandler( SecondFilterCriterion_PropertyChanged ); - this.RaisePropertyChanged( "SecondFilterCriterion" ); - } - } - } - - private void SecondFilterCriterion_PropertyChanged( object sender, PropertyChangedEventArgs e ) - { - this.RaisePropertyChanged( "SecondFilterCriterion" ); - } - - private FilterCriterion m_secondFilterCriterion; // = null; - - #endregion SecondFilterCriterion Property - - public override string ToExpression( CultureInfo culture ) - { - if( ( this.FirstFilterCriterion == null ) || ( this.SecondFilterCriterion == null ) ) - return ""; - - StringBuilder builder = new StringBuilder( this.FirstFilterCriterion.ToExpression( culture ) ); - builder.Append( " OR " ); - builder.Append( this.SecondFilterCriterion.ToExpression( culture ) ); - - return builder.ToString(); - } - - public override System.Linq.Expressions.Expression ToLinqExpression( System.Linq.IQueryable queryable, ParameterExpression parameterExpression, string propertyName ) - { - if( queryable == null ) - throw new ArgumentNullException( "queryable" ); - - if( parameterExpression == null ) - throw new ArgumentNullException( "parameterExpression" ); - - if( String.IsNullOrEmpty( propertyName ) ) - { - if( propertyName == null ) - throw new ArgumentNullException( "propertyName" ); - - throw new ArgumentException( "PropertyName must not be empty.", "propertyName" ); - } - - System.Linq.Expressions.Expression firstFilterLINQExpression = - ( m_firstFilterCriterion == null ) ? null : m_firstFilterCriterion.ToLinqExpression( queryable, parameterExpression, propertyName ); - - System.Linq.Expressions.Expression secondFilterLINQExpression = - ( m_secondFilterCriterion == null ) ? null : m_secondFilterCriterion.ToLinqExpression( queryable, parameterExpression, propertyName ); - - if( ( firstFilterLINQExpression != null ) && ( secondFilterLINQExpression != null ) ) - return System.Linq.Expressions.Expression.Or( firstFilterLINQExpression, secondFilterLINQExpression ); - - if( firstFilterLINQExpression != null ) - return firstFilterLINQExpression; - - // Will return null if both criterion or resulting LINQ expressions are null; - return secondFilterLINQExpression; - } - - public override bool IsMatch( object value ) - { - if( ( m_firstFilterCriterion == null ) || ( m_secondFilterCriterion == null ) ) - return false; - - return m_firstFilterCriterion.IsMatch( value ) || m_secondFilterCriterion.IsMatch( value ); - } - - public override bool Equals( object obj ) - { - if( !base.Equals( obj ) ) - return false; - - OrFilterCriterion criterion = ( OrFilterCriterion )obj; - - return object.Equals( this.FirstFilterCriterion, criterion.FirstFilterCriterion ) - && object.Equals( this.SecondFilterCriterion, criterion.SecondFilterCriterion ); - } - - public override int GetHashCode() - { - int hash = base.GetHashCode(); - - if( this.FirstFilterCriterion != null ) - hash ^= this.FirstFilterCriterion.GetHashCode(); - - if( this.SecondFilterCriterion != null ) - hash ^= this.SecondFilterCriterion.GetHashCode(); - - return hash; - } - -#if DEBUG - public override string ToString() - { - StringBuilder stringBuilder = new StringBuilder( "OR( " ); - stringBuilder.Append( this.FirstFilterCriterion.ToString() ); - stringBuilder.Append( ", " ); - stringBuilder.Append( this.SecondFilterCriterion.ToString() ); - stringBuilder.Append( " )" ); - - return stringBuilder.ToString(); - } -#endif - - protected internal override void InitializeFrom( object[] parameters, Type defaultComparisonFilterCriterionType ) - { - Debug.Assert( parameters.Length == 2, "Should have been caught earlier during BuildCriterion." ); - - if( parameters.Length != 2 ) - throw new DataGridInternalException( "Missing operand for the OR operator." ); - - this.FirstFilterCriterion = FilterParser.ProduceCriterion( parameters[ 0 ], defaultComparisonFilterCriterionType ); - this.SecondFilterCriterion = FilterParser.ProduceCriterion( parameters[ 1 ], defaultComparisonFilterCriterionType ); - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/RelationalFilterCriterion.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/RelationalFilterCriterion.cs deleted file mode 100644 index 094f2859..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/RelationalFilterCriterion.cs +++ /dev/null @@ -1,231 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Diagnostics; -using System.Globalization; -using System.Windows.Markup; - -namespace Xceed.Wpf.DataGrid.FilterCriteria -{ - [ContentProperty( "Value" )] - public abstract class RelationalFilterCriterion : FilterCriterion - { - public RelationalFilterCriterion() - { - } - - public RelationalFilterCriterion( object value ) - { - this.Value = value; - } - - #region Value Property - - public object Value - { - get - { - return m_value; - } - - set - { - if( value != m_value ) - { - m_value = value; - m_comparableValue = value as IComparable; - this.RaisePropertyChanged( "Value" ); - } - } - } - - protected IComparable ComparableValue - { - get - { - return m_comparableValue; - } - } - - private object m_value; - private IComparable m_comparableValue; - - #endregion - - public override bool Equals( object obj ) - { - if( !base.Equals( obj ) ) - return false; - - RelationalFilterCriterion criterion = ( RelationalFilterCriterion )obj; - - return object.Equals( this.Value, criterion.Value ); - } - - public override int GetHashCode() - { - int hash = base.GetHashCode(); - - if( this.Value != null ) - hash ^= this.Value.GetHashCode(); - - return hash; - } - - // Can return null. - protected string GetValueForExpression( CultureInfo culture ) - { - string strValue = this.Value as string; - - if( ( this.Value == null ) || ( this.Value == DBNull.Value ) ) - { - strValue = "NULL"; - } - else if( strValue == null ) - { - Type dataType = this.Value.GetType(); - - if( dataType == typeof( DateTime ) ) - { - DateTime dateValue = ( DateTime )this.Value; - - // ISO 8601 format - if( ( dateValue.Hour > 0 ) - || ( dateValue.Minute > 0 ) - || ( dateValue.Second > 0 ) - || ( dateValue.Millisecond > 0 ) ) - { - strValue = ( ( DateTime )this.Value ).ToString( "yyyy-MM-ddTHH:mm:ss.FFFFFFF" ); - } - else - { - strValue = ( ( DateTime )this.Value ).ToString( "yyyy-MM-dd" ); - } - } - else - { - try - { - if( culture == null ) - { - strValue = Convert.ToString( this.Value ); - } - else - { - strValue = Convert.ToString( this.Value, culture ); - } - } - catch( OverflowException ) - { - } - catch( FormatException ) - { - } - } - } - - if( strValue != null ) - { - int index = strValue.Length - 1; - - if( strValue == "" ) - strValue = "\"\""; - - while( index >= 0 ) - { - if( strValue[ index ] == '"' ) - { - strValue = strValue.Insert( index, "\"" ); - } - - index--; - } - - if( strValue.Contains( " " ) ) - { - strValue = "\"" + strValue + "\""; - } - } - - return strValue; - } - - protected internal override void InitializeFrom( object[] parameters, Type defaultComparisonFilterCriterionType ) - { - if( parameters.Length != 1 ) - throw new DataGridException( string.Format( FilterParser.MissingRightOperandErrorText, this.GetType().Name ) ); - - Debug.Assert( !( parameters[ 0 ] is FilterCriterion ), "Should have been caught earlier during BuildCriterion." ); - - if( parameters[ 0 ] is FilterCriterion ) - throw new DataGridInternalException( "Comparison with the result of a filter criterion is not allowed." ); - - this.Value = parameters[ 0 ]; - } - - /// - /// Compare the specified value (left value) with the Value property (right value). - /// For instance, this method will return LessThan if value < this.Value. - /// - internal CompareResult Compare( object value ) - { - object value2 = this.Value; - - if( ( value == null ) || ( value == DBNull.Value ) || ( value as string == string.Empty ) ) - { - if( ( value2 == null ) || ( value2 == DBNull.Value ) || ( ( value2 as string ) == string.Empty ) ) - { - return CompareResult.EqualsTo; - } - else - { - return CompareResult.LessThan; - } - } - else - { - if( ( value2 == null ) || ( value2 == DBNull.Value ) ) - { - return CompareResult.GreaterThan; - } - else if( m_comparableValue == null ) - { - return object.Equals( value, value2 ) ? CompareResult.EqualsTo : CompareResult.DifferentThan; - } - else - { - int i = m_comparableValue.CompareTo( value ); - - if( i < 0 ) - { - // value2 is less than value1: value is greater than. - return CompareResult.GreaterThan; - } - else if( i == 0 ) - { - return CompareResult.EqualsTo; - } - else - { - // value2 is greater than value1: value is less than. - return CompareResult.LessThan; - } - } - } - } - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/StartsWithFilterCriterion.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/StartsWithFilterCriterion.cs deleted file mode 100644 index 4ebc046f..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterCriteria/StartsWithFilterCriterion.cs +++ /dev/null @@ -1,102 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Text; -using System.Diagnostics; -using System.Globalization; - -namespace Xceed.Wpf.DataGrid.FilterCriteria -{ - [CriterionDescriptor( "@*", FilterOperatorPrecedence.RelationalOperator, FilterTokenPriority.RelationalOperator )] - [DebuggerDisplay( "StartsWith( {Value} )" )] - public class StartsWithFilterCriterion : RelationalFilterCriterion - { - public StartsWithFilterCriterion() - : base() - { - } - - public StartsWithFilterCriterion( object value ) - : base( value ) - { - } - - public override string ToExpression( CultureInfo culture ) - { - string strValue = this.GetValueForExpression( culture ); - - return ( strValue == null ) ? "" : strValue + "*"; - } - - public override Expression ToLinqExpression( IQueryable queryable, ParameterExpression parameterExpression, string propertyName ) - { - if( queryable == null ) - throw new ArgumentNullException( "queryable" ); - - if( parameterExpression == null ) - throw new ArgumentNullException( "parameterExpression" ); - - if( String.IsNullOrEmpty( propertyName ) ) - { - if( propertyName == null ) - throw new ArgumentNullException( "propertyName" ); - - throw new ArgumentException( "PropertyName must not be empty.", "propertyName" ); - } - - string queriedValue = this.Value as string; - - - if( queriedValue == null ) - queriedValue = string.Empty; - else - queriedValue = queriedValue.Remove( queriedValue.LastIndexOf( '*' ) ); - - return queryable.CreateStartsWithExpression( parameterExpression, propertyName, queriedValue ); - } - - public override bool IsMatch( object value ) - { - if( value == null ) - return false; - - if( this.Value == null ) - return true; - - string searchedValue = this.Value.ToString().ToLower(); - - if( searchedValue.Length == 0 ) - return true; - - string strValue = value.ToString().ToLower(); - return strValue.StartsWith( searchedValue, true, CultureInfo.CurrentCulture ); - } -#if DEBUG - public override string ToString() - { - System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder( "StartsWith( " ); - stringBuilder.Append( ( this.Value == null ) ? "#NULL#" : this.Value.ToString() ); - stringBuilder.Append( " )" ); - - return stringBuilder.ToString(); - } -#endif - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterParser.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterParser.cs deleted file mode 100644 index 3ded1d98..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterParser.cs +++ /dev/null @@ -1,812 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.Globalization; -using System.Text; -using Xceed.Wpf.DataGrid.FilterCriteria; - -namespace Xceed.Wpf.DataGrid -{ - internal static partial class FilterParser - { - static FilterParser() - { - RegisteredFilterCriterionTypes.Add( typeof( AndFilterCriterion ) ); - RegisteredFilterCriterionTypes.Add( typeof( ContainsFilterCriterion ) ); - RegisteredFilterCriterionTypes.Add( typeof( DifferentThanFilterCriterion ) ); - RegisteredFilterCriterionTypes.Add( typeof( EqualToFilterCriterion ) ); - RegisteredFilterCriterionTypes.Add( typeof( GreaterThanOrEqualToFilterCriterion ) ); - RegisteredFilterCriterionTypes.Add( typeof( GreaterThanFilterCriterion ) ); - RegisteredFilterCriterionTypes.Add( typeof( LessThanOrEqualToFilterCriterion ) ); - RegisteredFilterCriterionTypes.Add( typeof( LessThanFilterCriterion ) ); - RegisteredFilterCriterionTypes.Add( typeof( NotFilterCriterion ) ); - RegisteredFilterCriterionTypes.Add( typeof( OrFilterCriterion ) ); - RegisteredFilterCriterionTypes.Add( typeof( EndsWithFilterCriterion ) ); - RegisteredFilterCriterionTypes.Add( typeof( StartsWithFilterCriterion ) ); - - } - - public static string LastError - { - get - { - return FilterParser.LastErrorString; - } - - set - { - // Always keep the error message that triggered the error state for this session. - if( string.IsNullOrEmpty( value ) || string.IsNullOrEmpty( FilterParser.LastErrorString ) ) - FilterParser.LastErrorString = value; - } - } - - public static FilterCriterion ProduceCriterion( object parameterValue, Type defaultComparisonFilterCriterionType ) - { - if( parameterValue is FilterCriterion ) - { - return ( FilterCriterion )parameterValue; - } - else - { - if( !typeof( RelationalFilterCriterion ).IsAssignableFrom( defaultComparisonFilterCriterionType ) ) - throw new DataGridInternalException( "The default FilterCriterion type should derived from RelationalFilterCriterion." ); - - return Activator.CreateInstance( defaultComparisonFilterCriterionType, parameterValue ) as RelationalFilterCriterion; - } - } - - // If culture is null, CurrentThread.CurrentCulture will be used when necessary. - public static FilterCriterion Parse( string expression, Type dataType, CultureInfo culture ) - { - List tokens = FilterParser.GetTokens( expression, dataType ); - return FilterParser.BuildCriterion( tokens, dataType, FilterParser.GetDefaultCriterionType( dataType ), culture ); - } - - public static FilterCriterion TryParse( string expression, Type dataType, CultureInfo culture ) - { - FilterCriterion filterCriterion = null; - FilterParser.LastError = null; - - try - { - filterCriterion = FilterParser.Parse( expression, dataType, culture ); - } - catch( Exception ex ) - { - FilterParser.LastError = ex.Message; - } - - return filterCriterion; - } - - private static List GetTokens( string expression, Type dataType ) - { - List tokens = new List(); - FilterParser.LastError = null; - - FilterParser.PrepareExpressionTokens( expression, tokens ); - FilterParser.Tokenize( tokens, dataType, FilterParser.GetDefaultCriterionType( dataType ) ); - FilterParser.TrimTokens( tokens ); - - return tokens; - } - - private static void TrimTokens( List tokens ) - { - RawToken rawToken; - - for( int index = tokens.Count - 1; index >= 0; index-- ) - { - rawToken = tokens[ index ] as RawToken; - - if( rawToken != null ) - { - rawToken.Value = rawToken.Value.Trim(); - - if( rawToken.Value.Length == 0 ) - tokens.RemoveAt( index ); - } - } - } - - private static void FillPrecedenceList( List precedences ) - { - foreach( Type type in FilterParser.RegisteredFilterCriterionTypes ) - { - CriterionDescriptorAttribute attribute = ( CriterionDescriptorAttribute )type.GetCustomAttributes( typeof( CriterionDescriptorAttribute ), true )[ 0 ]; - - if( !precedences.Contains( ( int )attribute.OperatorPrecedence ) ) - precedences.Add( ( int )attribute.OperatorPrecedence ); - } - - precedences.Sort(); - } - - private static void FillParserPriorityList( List parserPriorities ) - { - foreach( Type type in FilterParser.RegisteredFilterCriterionTypes ) - { - CriterionDescriptorAttribute attribute = ( CriterionDescriptorAttribute )type.GetCustomAttributes( typeof( CriterionDescriptorAttribute ), true )[ 0 ]; - - if( !parserPriorities.Contains( ( int )attribute.ParserPriority ) ) - { - parserPriorities.Add( ( int )attribute.ParserPriority ); - } - } - - parserPriorities.Sort(); - } - - /// - /// Transforms the specified expression into one or more preliminary Tokens (RawToken - /// or AtomicStringToken). - /// - private static void PrepareExpressionTokens( string expression, List tokens ) - { - // Start index in the expression when we exclude all added tokens so far. This - // value is only updated after closing an atomic string token. - int stringStartIndex = 0; - // count the number of double quotes simplified - int quotesCounter = 0; - // Index of the first found " starting from the current position (0 for the first). - int quoteIndex = 0; - // Index of the first non " character after a found ". - int quotesEnd = 0; - // Index of the first character after the opening ". - int quotesStart = 0; - bool quoteOpened = false; - - expression = expression.Trim(); - quoteIndex = expression.IndexOf( '"' ); - - while( quoteIndex >= 0 ) - { - quotesEnd = quoteIndex + 1; - - // Find the first non " character starting from the index found. - while( quotesEnd < expression.Length ) - { - if( expression[ quotesEnd ] != '"' ) - break; - - quotesEnd++; - } - - if( ( ( ( quotesEnd - quoteIndex > 1 ) && ( quoteOpened ) ) ) ) - { - // Transform the " couples to a single ". - StringBuilder temp = new StringBuilder( expression.Substring( 0, quoteIndex ) ); - - for( int i = 0; i < ( quotesEnd - quoteIndex ) / 2; i++ ) - { - temp.Append( '"' ); - quotesCounter++; - } - temp.Append( expression.Substring( quotesEnd ) ); - - // Manually add the excess " when we're handling an odd number of " (can only - // happen when forming an AtomicString). The quotesCounter indicates where the - // last quotes have to be added (in case of (Starts/Ends)With, the quotes were misplaced). - if( ( quotesEnd - quoteIndex ) % 2 != 0 ) - { - temp.Insert( quotesEnd - quotesCounter - 1, "\"" ); - quotesCounter = 0; - } - expression = temp.ToString(); - - // Continue looking from the first character after the last " couple. - quoteIndex = quoteIndex + ( quotesEnd - quoteIndex ) / 2; - } - - else - { - if( quoteOpened ) - { - tokens.Add( new AtomicStringToken( expression.Substring( quotesStart, quoteIndex - quotesStart ) ) ); - stringStartIndex = quoteIndex + 1; - } - else - { - if( quoteIndex > stringStartIndex ) - tokens.Add( new RawToken( expression.Substring( stringStartIndex, quoteIndex - stringStartIndex ) ) ); - - quotesStart = quoteIndex + 1; - } - - quoteOpened = !quoteOpened; - quoteIndex++; - } - - quoteIndex = expression.IndexOf( '"', quoteIndex ); - } - - if( quoteOpened ) - throw new DataGridException( FilterParser.MissingClosingQuotesErrorText ); - - if( ( stringStartIndex > 0 ) && ( stringStartIndex < expression.Length ) ) - { - if( stringStartIndex < expression.Length ) - tokens.Add( new RawToken( expression.Substring( stringStartIndex ) ) ); - } - - if( tokens.Count == 0 ) - { - tokens.Add( new RawToken( expression ) ); - } - } - - private static void Tokenize( List tokens, Type dataType, Type defaultCriterionType ) - { - if( !typeof( FilterCriterion ).IsAssignableFrom( defaultCriterionType ) ) - throw new DataGridInternalException( "The default criterion type should be derived from the FilterCriterion class." ); - - List parserPriorities = new List(); - FilterParser.FillParserPriorityList( parserPriorities ); - - FilterParser.Tokenize( parserPriorities, tokens ); - - if( ( tokens.Count == 1 ) && ( tokens[ 0 ] is ValueToken ) ) - { - if( defaultCriterionType == typeof( ContainsFilterCriterion ) ) - { - // ContainsFilterCriterion has no keyword associated; it won't be handled when - // building the criterion. Initialize it with the Value already in it. - FilterCriterionToken containsToken = new FilterCriterionToken( ( FilterCriterion )Activator.CreateInstance( defaultCriterionType, ( ( ValueToken )tokens[ 0 ] ).Value ) ); - tokens.Clear(); - tokens.Add( containsToken ); - } - else - { - // Insert the default token previous to the value. - FilterCriterionToken defaultToken = new FilterCriterionToken( ( FilterCriterion )Activator.CreateInstance( defaultCriterionType ) ); - tokens.Insert( 0, defaultToken ); - } - } - } - - private static void Tokenize( List parserPriorities, List tokens ) - { - for( int index = 0; index < parserPriorities.Count; index++ ) - { - int curParserPriority = parserPriorities[ index ]; - bool tokenAdded = false; - - do - { - tokenAdded = false; - - for( int tokenIndex = 0; tokenIndex < tokens.Count; tokenIndex++ ) - { - RawToken rawToken = tokens[ tokenIndex ] as RawToken; - Token precedentToken = ( tokenIndex > 0 ) ? tokens[ tokenIndex - 1 ] : null; - if( rawToken != null ) - { - FilterCriterionToken filterToken; - int startIndex; - int length; - - - if( FilterParser.ExtractFirstCriterion( precedentToken, rawToken, curParserPriority, out filterToken, out startIndex, out length ) ) - { - tokens.RemoveAt( tokenIndex ); - - if( startIndex > 0 ) - { - tokens.Insert( tokenIndex, new RawToken( rawToken.Value.Substring( 0, startIndex ) ) ); - tokenIndex++; - } - - tokens.Insert( tokenIndex, filterToken ); - tokenIndex++; - - if( startIndex + length < rawToken.Value.Length ) - tokens.Insert( tokenIndex, new RawToken( rawToken.Value.Substring( startIndex + length ) ) ); - - tokenAdded = true; - break; - } - } - } - } - while( tokenAdded ); - } - } - - private static bool ExtractFirstCriterion( Token precedentToken, RawToken rawToken, int parserPriority, out FilterCriterionToken filterToken, out int startIndex, out int length ) - { - //RawToken rawToken = rawTokens[ tokenIndex ] as RawToken; - Type foundCriterionType = null; - filterToken = null; - startIndex = int.MaxValue; - length = 0; - - foreach( Type type in FilterParser.RegisteredFilterCriterionTypes ) - { - CriterionDescriptorAttribute attribute = ( CriterionDescriptorAttribute )type.GetCustomAttributes( typeof( CriterionDescriptorAttribute ), true )[ 0 ]; - - if( ( int )attribute.ParserPriority == parserPriority ) - { - if( !string.IsNullOrEmpty( attribute.Pattern ) ) - { - string separator = attribute.Pattern.Replace( "@", "" ); - int foundIndex = -1; - - if( attribute.Pattern.StartsWith( "@" ) ) - { - // The keyword can be anywhere in the token (there can be characters - // before the token). - foundIndex = rawToken.Value.IndexOf( separator ); - } - //else if( ( rawTokens[ tokenIndex + 1 ] as AtomicStringToken ) != null ) - //{ - - //} - else - { - // The keyword must be the first non whitespace character. - if( rawToken.Value.TrimStart( null ).StartsWith( separator ) ) - { - foundIndex = rawToken.Value.IndexOf( separator ); - } - } - - if( ( foundIndex >= 0 ) && - ( ( foundIndex < startIndex ) || - ( ( foundIndex == startIndex ) && ( separator.Length > length ) ) ) ) - { - if( type == typeof( EndsWithFilterCriterion ) && ( precedentToken as AtomicStringToken ) != null ) - foundCriterionType = typeof( StartsWithFilterCriterion ); - else - foundCriterionType = type; - startIndex = foundIndex; - length = separator.Length; - } - } - else - { - if( type != typeof( ContainsFilterCriterion ) ) - throw new DataGridInternalException( "Missing pattern in attribute: " + type.Name ); - } - } - } - - if( foundCriterionType != null ) - filterToken = new FilterCriterionToken( ( FilterCriterion )Activator.CreateInstance( foundCriterionType ) ); - - return ( filterToken != null ); - } - - private static FilterCriterion BuildCriterion( List tokens, Type dataType, Type defaultCriterionType, CultureInfo culture ) - { - FilterCriterion filterCriterion = null; - ReferenceList initializedCriteria = new ReferenceList(); - List precedences = new List(); - FilterParser.FillPrecedenceList( precedences ); - - for( int index = 0; index < precedences.Count; index++ ) - { - int curOperatorPrecedence = precedences[ index ]; - - foreach( Type type in FilterParser.RegisteredFilterCriterionTypes ) - { - CriterionDescriptorAttribute attribute = ( CriterionDescriptorAttribute )type.GetCustomAttributes( typeof( CriterionDescriptorAttribute ), true )[ 0 ]; - - if( ( int )attribute.OperatorPrecedence == curOperatorPrecedence ) - { - if( !string.IsNullOrEmpty( attribute.Pattern ) ) - { - bool tokenConsumed; - - do - { - tokenConsumed = false; - - for( int i = 0; i < tokens.Count; i++ ) - { - FilterCriterionToken filterToken = tokens[ i ] as FilterCriterionToken; - - if( ( filterToken != null ) && ( filterToken.FilterCriterion.GetType() == type ) && ( !initializedCriteria.Contains( filterToken.FilterCriterion ) ) ) - { - List parameters = new List(); - - if( attribute.Pattern.StartsWith( "@" ) ) - { - if( i <= 0 ) - throw new DataGridException( string.Format( FilterParser.MissingLeftOperandErrorText, type.Name ) ); - - if( tokens[ i - 1 ] is ValueToken ) - { - FilterParser.AddValueToParameters( parameters, ( ValueToken )tokens[ i - 1 ], dataType, culture ); - } - else - { - parameters.Add( ( ( FilterCriterionToken )tokens[ i - 1 ] ).FilterCriterion ); - } - - tokens.RemoveAt( i - 1 ); - i--; - } - - if( attribute.Pattern.EndsWith( "@" ) ) - { - if( i + 1 >= tokens.Count ) - throw new DataGridException( string.Format( FilterParser.MissingRightOperandErrorText, type.Name ) ); - - if( tokens[ i + 1 ] is ValueToken ) - { - FilterParser.AddValueToParameters( parameters, ( ValueToken )tokens[ i + 1 ], dataType, culture ); - } - else - { - parameters.Add( ( ( FilterCriterionToken )tokens[ i + 1 ] ).FilterCriterion ); - } - - tokens.RemoveAt( i + 1 ); - i--; - } - - filterToken.FilterCriterion.InitializeFrom( parameters.ToArray(), defaultCriterionType ); - initializedCriteria.Add( filterToken.FilterCriterion ); - tokenConsumed = true; - break; - } - } - } - while( tokenConsumed ); - } - else - { - if( type != typeof( ContainsFilterCriterion ) ) - throw new DataGridInternalException( "Missing pattern in attribute: " + type.Name ); - } - } - } - } - - if( ( tokens.Count == 1 ) && ( tokens[ 0 ] is FilterCriterionToken ) ) - { - filterCriterion = ( ( FilterCriterionToken )tokens[ 0 ] ).FilterCriterion; - } - else - { - throw new DataGridException( FilterParser.InvalidExpressionErrorText ); - } - - return filterCriterion; - } - - private static void AddValueToParameters( List parameters, ValueToken token, Type dataType, CultureInfo culture ) - { - if( token.Value == "NULL" ) - { - parameters.Add( null ); - } - else if( dataType == typeof( string ) ) - { - parameters.Add( token.Value ); - } - else if( dataType == typeof( Guid ) ) - { - System.ComponentModel.GuidConverter converter = new System.ComponentModel.GuidConverter(); - - parameters.Add( converter.ConvertFrom( token.Value ) ); - } - else if( ( dataType == typeof( byte ) ) - || ( dataType == typeof( short ) ) - || ( dataType == typeof( bool ) ) - || ( dataType == typeof( int ) ) - || ( dataType == typeof( long ) ) - || ( dataType == typeof( float ) ) - || ( dataType == typeof( double ) ) - || ( dataType == typeof( decimal ) ) - || ( dataType == typeof( sbyte ) ) - || ( dataType == typeof( ushort ) ) - || ( dataType == typeof( uint ) ) - || ( dataType == typeof( ulong ) ) ) - { - try - { - parameters.Add( Convert.ChangeType( token.Value, dataType, culture ) ); - } - catch( OverflowException ) - { - throw new DataGridException( FilterParser.NumberOverflowErrorText ); - } - catch( FormatException ) - { - throw new DataGridException( FilterParser.InvalidNumberFormatErrorText ); - } - } - else if( dataType == typeof( char ) ) - { - if( token.Value.Length == 1 ) - { - parameters.Add( token.Value[ 0 ] ); - } - else - { - throw new DataGridException( string.Format( FilterParser.InvalidCharValueErrorText, token.Value ) ); - } - } - else if( dataType == typeof( DateTime ) ) - { - DateTime dateTime; - - try - { - if( culture == null ) - { - dateTime = DateTime.Parse( token.Value ); - } - else - { - dateTime = DateTime.Parse( token.Value, culture ); - } - } - catch( FormatException ) - { - throw new DataGridException( string.Format( FilterParser.InvalidDateTimeValueErrorText, token.Value ) ); - } - - parameters.Add( dateTime ); - } - } - - private static Type GetDefaultCriterionType( Type dataType ) - { - return dataType == typeof( string ) ? typeof( ContainsFilterCriterion ) : typeof( EqualToFilterCriterion ); - } - - private static CriterionTypeCollection RegisteredFilterCriterionTypes = new CriterionTypeCollection(); - private static string LastErrorString = null; - internal static string MissingClosingQuotesErrorText = "Missing closing quotes."; - internal static string MissingRightOperandErrorText = "Missing right operand for filter {0}."; - internal static string MissingLeftOperandErrorText = "Missing left operand for filter {0}."; - internal static string InvalidExpressionErrorText = "The expression cannot be resolved. Are you missing a logical operator?"; - internal static string InvalidCharValueErrorText = "{0} is not a valid character value."; - internal static string InvalidDateTimeValueErrorText = "Invalid date/time value. It is recommended to use the following format: yyyy-MM-ddTHH:mm:ss.fff."; - internal static string InvalidNumberFormatErrorText = "Invalid number format."; - internal static string InvalidEnumValueErrorText = "Invalid enum value."; - internal static string NumberOverflowErrorText = "Number value is out of range."; - - #region CriterionTypeCollection Nested Type - - private class CriterionTypeCollection : Collection - { - protected override void InsertItem( int index, Type item ) - { - if( !typeof( FilterCriterion ).IsAssignableFrom( item ) ) - throw new ArgumentException( "Must be derived from FilterCriterion.", "item" ); - - if( item.GetCustomAttributes( typeof( CriterionDescriptorAttribute ), false ).Length == 0 ) - throw new ArgumentException( "Must have the CriterionDescriptor attribute.", "item" ); - - base.InsertItem( index, item ); - } - - protected override void SetItem( int index, Type item ) - { - if( !typeof( FilterCriterion ).IsAssignableFrom( item ) ) - throw new ArgumentException( "Must be derived from FilterCriterion.", "item" ); - - if( item.GetCustomAttributes( typeof( CriterionDescriptorAttribute ), false ).Length == 0 ) - throw new ArgumentException( "Must have the CriterionDescriptor attribute.", "item" ); - - base.SetItem( index, item ); - } - } - - #endregion CriterionTypeCollection Nested Type - - #region Token Nested Type - - private abstract class Token - { - } - - #endregion - - #region ValueToken Nested Type - - private abstract class ValueToken : Token - { - public ValueToken() - { - } - - public ValueToken( string value ) - { - this.Value = value; - } - - public string Value - { - get; - set; - } - } - - #endregion - - #region RawToken Nested Type - - /// - /// A token containing still unprocessed complete or partial expression or an actual - /// value that is not between "". - /// - private class RawToken : ValueToken - { - public RawToken() - { - } - - public RawToken( string value ) - : base( value ) - { - } - } - - #endregion - - #region AtomicStringToken - - /// - /// A token containing a value that will not be processed by the parser because it - /// was between "". - /// - private class AtomicStringToken : ValueToken - { - public AtomicStringToken() - { - } - - public AtomicStringToken( string value ) - : base( value ) - { - } - } - - #endregion - - #region FilterCriterionToken Nested Type - - private class FilterCriterionToken : Token - { - public FilterCriterionToken() - { - } - - public FilterCriterionToken( FilterCriterion filterCriterion ) - { - this.FilterCriterion = filterCriterion; - } - - public FilterCriterion FilterCriterion - { - get; - set; - } - } - - #endregion - - #region ReferenceList Nested Type - - // This list will prevent the same object of being added twice. - // To compare objects (in IndexOf, Add, Remove and Contains), it will use the ReferenceEquals() method. - // Naturally, this class won't behave properly with ValueType because of boxing. - private class ReferenceList : ICollection - { - public int IndexOf( T item ) - { - int foundIndex = -1; - - for( int i = 0; i < m_internalList.Count; i++ ) - { - if( object.ReferenceEquals( item, m_internalList[ i ] ) ) - { - foundIndex = i; - break; - } - } - - return foundIndex; - } - - #region ICollection Members - - public void Add( T item ) - { - if( this.Contains( item ) ) - throw new InvalidOperationException( "An attempt was made to add an item that is already contained in the list." ); - - m_internalList.Add( item ); - } - - public void Clear() - { - m_internalList.Clear(); - } - - public bool Contains( T item ) - { - return ( this.IndexOf( item ) > -1 ); - } - - public void CopyTo( T[] array, int arrayIndex ) - { - m_internalList.CopyTo( array, arrayIndex ); - } - - public int Count - { - get - { - return m_internalList.Count; - } - } - - public bool IsReadOnly - { - get - { - return false; - } - } - - public bool Remove( T item ) - { - int index = this.IndexOf( item ); - - if( index > -1 ) - { - m_internalList.RemoveAt( index ); - } - - return ( index > -1 ); - } - - #endregion - - #region IEnumerable Members - - public IEnumerator GetEnumerator() - { - return m_internalList.GetEnumerator(); - } - - #endregion - - #region IEnumerable Members - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return m_internalList.GetEnumerator(); - } - - #endregion - - private List m_internalList = new List(); - } - - #endregion - } -} diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterParserTestWindow.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterParserTestWindow.cs deleted file mode 100644 index e4116f0e..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/FilterParserTestWindow.cs +++ /dev/null @@ -1,306 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 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 - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -#if DEBUG - -using System; -using System.Globalization; -using System.IO; -using System.Threading; -using System.Windows; -using System.Windows.Markup; -using System.Windows.Controls; -using System.Xml; - -using Xceed.Wpf.DataGrid.FilterCriteria; - -namespace Xceed.Wpf.DataGrid -{ - public class FilterParserTestWindow : Window - { - public FilterParserTestWindow() - { - string mainGridXaml = -@" - - - - - - - - - - - - - -Here, you can test various expression that will be parsed. -The result of the parsing will be shown in the second TextBox. -Don't forget to check the Output Window for errors that could have occured during the -automated tests. Untested expressions by the automated tests should be added when found. - - - - - - - - - - - - - - - - - - - - - - - - - - - Invariant - fr-FR - en-US - - - - - - - - - - - - - - - -