├── source
├── Components
│ ├── BusinessLib
│ │ ├── Resources
│ │ │ ├── lokasyon.zip
│ │ │ ├── lokasyon.sql.gz
│ │ │ └── readme.txt
│ │ ├── Models
│ │ │ ├── LocationType.cs
│ │ │ └── MetaLocationModel.cs
│ │ ├── Properties
│ │ │ └── AssemblyInfo.cs
│ │ ├── BusinessLib.csproj
│ │ └── database.cs
│ └── FilterTreeViewLib
│ │ ├── Resources
│ │ ├── ZoomIn.ico
│ │ ├── ZoomIn_256x.png
│ │ ├── ZoomIn_48x.png
│ │ ├── ZoomIn_64x.png
│ │ └── Locations
│ │ │ ├── appbar.base.select.png
│ │ │ ├── appbar.chess.rook.png
│ │ │ └── appbar.city.sanfrancisco.png
│ │ ├── packages.config
│ │ ├── Interfaces
│ │ ├── IHasDummyChild.cs
│ │ └── ISelectionRange.cs
│ │ ├── ViewModels
│ │ ├── Tree
│ │ │ ├── Search
│ │ │ │ ├── Enums
│ │ │ │ │ ├── SearchMatch.cs
│ │ │ │ │ └── MatchType.cs
│ │ │ │ ├── SearchResult.cs
│ │ │ │ ├── SelectionRange.cs
│ │ │ │ ├── SearchParams.cs
│ │ │ │ └── StringMatchItem.cs
│ │ │ ├── MetaLocationRootViewModel.cs
│ │ │ └── MetaLocationViewModel.cs
│ │ ├── Base
│ │ │ ├── RelayCommand.cs
│ │ │ └── BaseViewModel.cs
│ │ └── AppBaseViewModel.cs
│ │ ├── Converters
│ │ ├── CountToBoolConverter.cs
│ │ ├── InverseBooleanConverter.cs
│ │ ├── BoolToVisibilityConverter.cs
│ │ └── LocationTypeToImageConverter.cs
│ │ ├── Properties
│ │ └── AssemblyInfo.cs
│ │ ├── Views
│ │ └── BindingProxy.cs
│ │ ├── Behaviors
│ │ ├── TreeViewItemExpanded.cs
│ │ ├── HighlightTextBlockBehavior.cs
│ │ └── TextChangedCommand.cs
│ │ └── FilterTreeViewLib.csproj
├── FilterTreeView
│ ├── packages.config
│ ├── App.config
│ ├── Properties
│ │ ├── Settings.settings
│ │ ├── Settings.Designer.cs
│ │ ├── AssemblyInfo.cs
│ │ ├── Resources.Designer.cs
│ │ └── Resources.resx
│ ├── App.xaml.cs
│ ├── FilterTreeView.csproj.user
│ ├── MainWindow.xaml.cs
│ ├── App.xaml
│ ├── FilterTreeView.csproj
│ ├── ViewModels
│ │ └── AppViewModel.cs
│ ├── Tasks
│ │ ├── OneTaskLimitedScheduler.cs
│ │ └── OneTaskProcessor.cs
│ └── MainWindow.xaml
├── CleanAll.bat
└── FilterTreeView.sln
├── .gitignore
├── LICENSE
└── README.md
/source/Components/BusinessLib/Resources/lokasyon.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dirkster99/FilterTreeView/HEAD/source/Components/BusinessLib/Resources/lokasyon.zip
--------------------------------------------------------------------------------
/source/Components/BusinessLib/Resources/lokasyon.sql.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dirkster99/FilterTreeView/HEAD/source/Components/BusinessLib/Resources/lokasyon.sql.gz
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/Resources/ZoomIn.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dirkster99/FilterTreeView/HEAD/source/Components/FilterTreeViewLib/Resources/ZoomIn.ico
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/Resources/ZoomIn_256x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dirkster99/FilterTreeView/HEAD/source/Components/FilterTreeViewLib/Resources/ZoomIn_256x.png
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/Resources/ZoomIn_48x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dirkster99/FilterTreeView/HEAD/source/Components/FilterTreeViewLib/Resources/ZoomIn_48x.png
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/Resources/ZoomIn_64x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dirkster99/FilterTreeView/HEAD/source/Components/FilterTreeViewLib/Resources/ZoomIn_64x.png
--------------------------------------------------------------------------------
/source/FilterTreeView/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/Resources/Locations/appbar.base.select.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dirkster99/FilterTreeView/HEAD/source/Components/FilterTreeViewLib/Resources/Locations/appbar.base.select.png
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/Resources/Locations/appbar.chess.rook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dirkster99/FilterTreeView/HEAD/source/Components/FilterTreeViewLib/Resources/Locations/appbar.chess.rook.png
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/Resources/Locations/appbar.city.sanfrancisco.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dirkster99/FilterTreeView/HEAD/source/Components/FilterTreeViewLib/Resources/Locations/appbar.city.sanfrancisco.png
--------------------------------------------------------------------------------
/source/FilterTreeView/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/source/FilterTreeView/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/source/FilterTreeView/App.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeView
2 | {
3 | using System.Windows;
4 |
5 | ///
6 | /// Interaction logic for App.xaml
7 | ///
8 | public partial class App : Application
9 | {
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/source/FilterTreeView/FilterTreeView.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ProjectFiles
5 |
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | source/packages/
2 | packages/
3 | 00_Release/
4 | 01_Nuget/
5 | debug/
6 | release/
7 | build/
8 | bin/
9 | obj/
10 | cache/
11 | log/
12 | tmp/
13 | /source/.vs/
14 | .vs/
15 |
16 | *~
17 | *.lock
18 | *.DS_Store
19 | *.swp
20 | *.out
21 | *.sou
22 | *.suo
23 | *.sqlite
24 |
--------------------------------------------------------------------------------
/source/Components/BusinessLib/Resources/readme.txt:
--------------------------------------------------------------------------------
1 |
2 | The sample data in *lokasyon.sql.gz* directory was drawn from here:
3 | https://code.google.com/archive/p/worlddb/downloads
4 |
5 | This data was converted to XML using a custom sqlite converter program.
6 | The result of that conversion was: lokasyon.zip
7 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/Interfaces/IHasDummyChild.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeViewLib.Interfaces
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | public interface IHasDummyChild
10 | {
11 |
12 | ///
13 | /// Determines whether this item has a dummy child below or not.
14 | ///
15 | bool HasDummyChild { get; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/source/Components/BusinessLib/Models/LocationType.cs:
--------------------------------------------------------------------------------
1 | namespace BusinessLib.Models
2 | {
3 | ///
4 | /// Determines the type of location in a collection entry.
5 | ///
6 | public enum LocationType
7 | {
8 | Unknown = 1000,
9 |
10 | ///
11 | /// This location refers to a country on our little world called Earth.
12 | ///
13 | Country = 100,
14 |
15 | ///
16 | /// This location refers to a region that is part of a country.
17 | ///
18 | Region = 10,
19 |
20 | ///
21 | /// This location refers to a city (e.g. Berlin) located within
22 | /// a region.
23 | ///
24 | City = 0
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/ViewModels/Tree/Search/Enums/SearchMatch.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeViewLib.ViewModelsSearch.SearchModels.Enums
2 | {
3 | ///
4 | /// Determines the type of match that should be implemented to
5 | /// match a node to a search string during a search.
6 | ///
7 | public enum SearchMatch
8 | {
9 | ///
10 | /// The string searched is contained somewhere in within a nodes string.
11 | ///
12 | StringIsContained = 0,
13 |
14 | ///
15 | /// The string searched is an exact match within a nodes string
16 | /// (length of strings is identical and ALL letters are present
17 | /// in the given order - but case folding may still be applied).
18 | ///
19 | StringIsMatched = 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/Converters/CountToBoolConverter.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeViewLib.Converters
2 | {
3 | using System;
4 | using System.Globalization;
5 | using System.Windows.Data;
6 |
7 | public class CountToBoolConverter : IValueConverter
8 | {
9 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
10 | {
11 | if (value == null)
12 | return false;
13 |
14 | if (value is int == false)
15 | return false;
16 |
17 | int convertValue = (int)value;
18 |
19 | if (convertValue > 0)
20 | return true;
21 |
22 | return false;
23 | }
24 |
25 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
26 | {
27 | throw new NotImplementedException();
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/Converters/InverseBooleanConverter.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeViewLib.Converters
2 | {
3 | using System;
4 | using System.Windows.Data;
5 |
6 | [ValueConversion(typeof(bool), typeof(bool))]
7 | public class InverseBooleanConverter : IValueConverter
8 | {
9 | #region IValueConverter Members
10 |
11 | public object Convert(object value, Type targetType, object parameter,
12 | System.Globalization.CultureInfo culture)
13 | {
14 | if (targetType != typeof(bool))
15 | throw new InvalidOperationException("The target must be a boolean");
16 |
17 | return !(bool)value;
18 | }
19 |
20 | public object ConvertBack(object value, Type targetType, object parameter,
21 | System.Globalization.CultureInfo culture)
22 | {
23 | throw new NotSupportedException();
24 | }
25 |
26 | #endregion
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/source/FilterTreeView/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeView
2 | {
3 | using System;
4 | using System.Windows;
5 |
6 | ///
7 | /// Interaction logic for MainWindow.xaml
8 | ///
9 | public partial class MainWindow : Window
10 | {
11 | public MainWindow()
12 | {
13 | InitializeComponent();
14 |
15 | Loaded += MainWindow_Loaded;
16 | Unloaded += MainWindow_Unloaded;
17 | }
18 |
19 | private void MainWindow_Unloaded(object sender, RoutedEventArgs e)
20 | {
21 | var appVM = this.DataContext as IDisposable;
22 |
23 | if (appVM != null)
24 | appVM.Dispose();
25 | }
26 |
27 | private async void MainWindow_Loaded(object sender, RoutedEventArgs e)
28 | {
29 | Loaded -= MainWindow_Loaded;
30 |
31 | var appVM = new FilterTreeView.ViewModels.AppViewModel();
32 | this.DataContext = appVM;
33 |
34 | await appVM.LoadSampleDataAsync();
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/source/FilterTreeView/App.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/source/FilterTreeView/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace FilterTreeView.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.1.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/Converters/BoolToVisibilityConverter.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeViewLib.Converters
2 | {
3 | using System;
4 | using System.Globalization;
5 | using System.Windows;
6 | using System.Windows.Data;
7 |
8 | public class BoolToVisibilityConverter : IValueConverter
9 | {
10 | public BoolToVisibilityConverter()
11 | {
12 | this.True = Visibility.Visible;
13 | this.False = Visibility.Collapsed;
14 | }
15 |
16 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
17 | {
18 | if (value == null)
19 | return Binding.DoNothing;
20 |
21 | if (value is bool == false)
22 | return Binding.DoNothing;
23 |
24 | bool input = (bool)value;
25 |
26 | if (input == true)
27 | return True;
28 |
29 | return False;
30 | }
31 |
32 | public Visibility True { get; set; }
33 |
34 | public Visibility False { get; set; }
35 |
36 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
37 | {
38 | throw new NotImplementedException();
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/ViewModels/Tree/Search/Enums/MatchType.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeViewLib.ViewModelsSearch.SearchModels.Enums
2 | {
3 | ///
4 | /// Determines whether a givem node has a match with regard to search parameters
5 | /// - search string and
6 | /// - additional search options (eg.: string contained, exact match)
7 | ///
8 | /// This includes a reference to child items that might contain a
9 | /// match while the node itself may only be the parent of a child
10 | /// with an actual match.
11 | ///
12 | public enum MatchType
13 | {
14 | ///
15 | /// The node (and its children) contains no match.
16 | ///
17 | NoMatch = 0,
18 |
19 | ///
20 | /// The node was macth against the search parameters.
21 | ///
22 | NodeMatch = 1,
23 |
24 | ///
25 | /// A child node or children nodes of this node contain a match
26 | /// BUT this node does not contain a match.
27 | ///
28 | SubNodeMatch = 2,
29 |
30 | ///
31 | /// A child node or children nodes of this node contain a match
32 | /// AND this node does also contain a match.
33 | ///
34 | Node_AND_SubNodeMatch = 4
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/source/CleanAll.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 | pushd "%~dp0"
3 | ECHO.
4 | ECHO.
5 | ECHO.
6 | ECHO This script deletes all temporary build files in the .vs folder and the
7 | ECHO BIN and OBJ folders contained in the following projects
8 | ECHO.
9 | ECHO Components\BusinessLib
10 | ECHO Components\FilterTreeViewLib
11 | ECHO FilterTreeView
12 | ECHO.
13 | REM Ask the user if hes really sure to continue beyond this point XXXXXXXX
14 | set /p choice=Are you sure to continue (Y/N)?
15 | if not '%choice%'=='Y' Goto EndOfBatch
16 | REM Script does not continue unless user types 'Y' in upper case letter
17 | ECHO.
18 | ECHO XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
19 | ECHO.
20 | ECHO XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
21 | ECHO.
22 | ECHO Removing vs settings folder with *.sou file
23 | ECHO.
24 | RMDIR /S /Q .vs
25 |
26 | ECHO.
27 | ECHO Deleting BIN and OBJ Folders in BusinessLib
28 | ECHO.
29 | RMDIR /S /Q "Components\BusinessLib\bin"
30 | RMDIR /S /Q "Components\BusinessLib\obj"
31 |
32 | ECHO.
33 | ECHO Deleting BIN and OBJ Folders in FilterTreeViewLib
34 | ECHO.
35 | RMDIR /S /Q "Components\FilterTreeViewLib\bin"
36 | RMDIR /S /Q "Components\FilterTreeViewLib\obj"
37 |
38 | ECHO.
39 | ECHO Deleting BIN and OBJ Folders in FilterTreeView
40 | ECHO.
41 | RMDIR /S /Q ".\FilterTreeView\bin"
42 | RMDIR /S /Q ".\FilterTreeView\obj"
43 |
44 | PAUSE
45 |
46 | :EndOfBatch
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://ci.appveyor.com/project/Dirkster99/filtertreeview) [](https://github.com/Dirkster99/FilterTreeView/releases/latest)
2 |
3 | # FilterTreeView
4 | This is a WPF/MVVM Search and Filter TreeView Reference Application
5 |
6 | See Codeproject articles:
7 | * Advanced WPF TreeViews Part 3 of n
8 | * A Highlightable WPF/MVVM TextBlock
9 |
10 | for more details or watch a screen captured video on youtube.
11 |
12 | ## TreeLib
13 | See also TreeLib project for Tree Traversal methods used in this project.
14 |
15 | ## City Search (String is contained):
16 |
17 |
18 | * 781 Saint
19 | * 267 los
20 | * 48 Washington
21 | * 32 Berlin
22 | * 22 Holland
23 | * 29 Paris
24 | * 23 London
25 | * 15 Brighton
26 | * 11 Hamburg
27 | * 10 Bremen
28 | * 17 Kiel
29 | * 14 Francisco
30 | * 9 Madrid
31 | * 7 Liverpool
32 | * 7 Amsterdam
33 | * 7 Australia
34 | * 3 Muenster
35 |
--------------------------------------------------------------------------------
/source/Components/BusinessLib/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("BusinessLib")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("BusinessLib")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("70cc82cc-9efe-461f-a959-f64a06894621")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("FilterTreeViewLib")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("FilterTreeViewLib")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("c5030463-0469-4afa-92f4-f6b55a6b4c89")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/Views/BindingProxy.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeViewLib.Views
2 | {
3 | using System.Windows;
4 |
5 | ///
6 | /// Implements an XAML proxy which can be used to bind items (TreeViewItem, ListViewItem etc)
7 | /// with a viewmodel that manages the collecrions.
8 | ///
9 | /// Source: http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/
10 | /// Issue: http://stackoverflow.com/questions/9994241/mvvm-binding-command-to-contextmenu-item
11 | ///
12 | public class BindingProxy : Freezable
13 | {
14 | ///
15 | /// Backing storage of the Data dependency property.
16 | ///
17 | /// Gets/sets the data object this class is forwarding to everyone
18 | /// who has a reference to this object.
19 | ///
20 | public static readonly DependencyProperty DataProperty =
21 | DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
22 |
23 | ///
24 | /// Gets/sets the data object this class is forwarding to everyone
25 | /// who has a reference to this object.
26 | ///
27 | public object Data
28 | {
29 | get { return (object)GetValue(DataProperty); }
30 | set { SetValue(DataProperty, value); }
31 | }
32 |
33 | ///
34 | /// Overrides of Freezable
35 | ///
36 | ///
37 | protected override Freezable CreateInstanceCore()
38 | {
39 | return new BindingProxy();
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/Interfaces/ISelectionRange.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeViewLib.Interfaces
2 | {
3 | using System;
4 | using System.Windows.Media;
5 |
6 | ///
7 | /// Defines a range that can be used to indicate
8 | /// the start and end of a text selection or any other kind of range.
9 | ///
10 | public interface ISelectionRange : ICloneable
11 | {
12 | ///
13 | /// Gets the start of the indicated range.
14 | ///
15 | int Start { get; }
16 |
17 | ///
18 | /// Gets the end of the indicated range.
19 | ///
20 | int End { get; }
21 |
22 | ///
23 | /// Gets a bool value to determine whether DarkSkin default
24 | /// value for property should
25 | /// be applied or not.
26 | ///
27 | bool DarkSkin { get; }
28 |
29 | ///
30 | /// Gets the background color that is applied to the background brush,
31 | /// which should be applied when no match is indicated
32 | /// (this can be default(Color) in which case standard selection Brush
33 | /// is applied).
34 | ///
35 | /// Note:
36 | /// Standard selection background color on light skin: 208, 247, 255
37 | /// Standard selection background color on dark skin: 254, 252, 200
38 | ///
39 | Color SelectionBackground { get; }
40 |
41 | ///
42 | /// Gets the background color that is applied to the background brush.
43 | /// which should be applied when no match is indicated
44 | /// (this can be default(Color) in which case Transparent is applied).
45 | ///
46 | Color NormalBackground { get; }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/ViewModels/Tree/Search/SearchResult.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeViewLib.ViewModelsSearch.SearchModels
2 | {
3 | ///
4 | /// Models the results of a search in terms of the actual string and options
5 | /// being searched and the results found.
6 | ///
7 | public class SearchResult
8 | {
9 | #region constructors
10 | ///
11 | /// Class constructor
12 | ///
13 | ///
14 | ///
15 | public SearchResult(SearchParams searchParams, int results)
16 | : this()
17 | {
18 | Options = searchParams;
19 | Results = results;
20 | }
21 |
22 | ///
23 | /// Hidden Class constructor
24 | ///
25 | protected SearchResult()
26 | {
27 | }
28 | #endregion constructors
29 |
30 | ///
31 | /// Gets the searchterm that was usedt o find the shown results.
32 | ///
33 | public string SearchTerm
34 | {
35 | get
36 | {
37 | if (Options != null)
38 | return Options.SearchString;
39 |
40 | return string.Empty;
41 | }
42 | }
43 |
44 | ///
45 | /// Gets the ORIGONAL searchterm that was used to find the shown results.
46 | ///
47 | public string OriginalSearchString
48 | {
49 | get
50 | {
51 | if (Options != null)
52 | return Options.OriginalSearchString;
53 |
54 | return string.Empty;
55 | }
56 | }
57 |
58 | ///
59 | /// Gets the search parameters and the search term for this result.
60 | ///
61 | public SearchParams Options { get; protected set; }
62 |
63 | ///
64 | /// Gets the number of matches found.
65 | ///
66 | public int Results { get; protected set; }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/Converters/LocationTypeToImageConverter.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeViewLib.Converters
2 | {
3 | using BusinessLib.Models;
4 | using System;
5 | using System.Globalization;
6 | using System.Windows;
7 | using System.Windows.Data;
8 |
9 | ///
10 | /// Converts an enum into its image resource.
11 | /// The corresponding image resource must be present in the applications's
12 | /// resource dictionary.
13 | ///
14 | [ValueConversion(typeof(LocationType), typeof(System.Windows.Media.Imaging.BitmapImage))]
15 | public class LocationTypeToImageConverter : IValueConverter
16 | {
17 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
18 | {
19 | if (value == null)
20 | return Binding.DoNothing;
21 |
22 | if (value is LocationType == false)
23 | return Binding.DoNothing;
24 |
25 | LocationType typeOfLocation = (LocationType)value;
26 | string locationIconName = string.Empty;
27 |
28 | try
29 | {
30 | switch (typeOfLocation)
31 | {
32 | case LocationType.Country:
33 | locationIconName = "CountryImage";
34 | break;
35 |
36 | case LocationType.Region:
37 | locationIconName = "RegionImage";
38 | break;
39 |
40 | case LocationType.City:
41 | locationIconName = "CityImage";
42 | break;
43 |
44 | case LocationType.Unknown:
45 | return Binding.DoNothing;
46 |
47 | default:
48 | throw new ArgumentOutOfRangeException(typeOfLocation.ToString());
49 | }
50 |
51 | return Application.Current.Resources[locationIconName];
52 | }
53 | catch
54 | {
55 | }
56 |
57 | return Binding.DoNothing;
58 | }
59 |
60 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
61 | {
62 | throw new NotImplementedException();
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/source/FilterTreeView/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 | using System.Windows;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("FilterTreeView")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("FilterTreeView")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | //In order to begin building localizable applications, set
23 | //CultureYouAreCodingWith in your .csproj file
24 | //inside a . For example, if you are using US english
25 | //in your source files, set the to en-US. Then uncomment
26 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
27 | //the line below to match the UICulture setting in the project file.
28 |
29 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
30 |
31 |
32 | [assembly: ThemeInfo(
33 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
34 | //(used if a resource is not found in the page,
35 | // or application resource dictionaries)
36 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
37 | //(used if a resource is not found in the page,
38 | // app, or any theme specific resource dictionaries)
39 | )]
40 |
41 |
42 | // Version information for an assembly consists of the following four values:
43 | //
44 | // Major Version
45 | // Minor Version
46 | // Build Number
47 | // Revision
48 | //
49 | // You can specify all the values or you can default the Build and Revision Numbers
50 | // by using the '*' as shown below:
51 | // [assembly: AssemblyVersion("1.0.*")]
52 | [assembly: AssemblyVersion("1.0.0.0")]
53 | [assembly: AssemblyFileVersion("1.0.0.0")]
54 |
--------------------------------------------------------------------------------
/source/FilterTreeView.sln:
--------------------------------------------------------------------------------
1 | Microsoft Visual Studio Solution File, Format Version 12.00
2 | # Visual Studio 15
3 | VisualStudioVersion = 15.0.27004.2009
4 | MinimumVisualStudioVersion = 10.0.40219.1
5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FilterTreeView", "FilterTreeView\FilterTreeView.csproj", "{9668A53D-608F-46B1-926C-14AC52CD35AE}"
6 | EndProject
7 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BusinessLib", "Components\BusinessLib\BusinessLib.csproj", "{70CC82CC-9EFE-461F-A959-F64A06894621}"
8 | EndProject
9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FilterTreeViewLib", "Components\FilterTreeViewLib\FilterTreeViewLib.csproj", "{C5030463-0469-4AFA-92F4-F6B55A6B4C89}"
10 | EndProject
11 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Components", "Components", "{F0EEB4AD-6E8F-47AC-BE12-98A0A15ABD95}"
12 | EndProject
13 | Global
14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
15 | Debug|Any CPU = Debug|Any CPU
16 | Release|Any CPU = Release|Any CPU
17 | EndGlobalSection
18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
19 | {9668A53D-608F-46B1-926C-14AC52CD35AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
20 | {9668A53D-608F-46B1-926C-14AC52CD35AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
21 | {9668A53D-608F-46B1-926C-14AC52CD35AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
22 | {9668A53D-608F-46B1-926C-14AC52CD35AE}.Release|Any CPU.Build.0 = Release|Any CPU
23 | {70CC82CC-9EFE-461F-A959-F64A06894621}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24 | {70CC82CC-9EFE-461F-A959-F64A06894621}.Debug|Any CPU.Build.0 = Debug|Any CPU
25 | {70CC82CC-9EFE-461F-A959-F64A06894621}.Release|Any CPU.ActiveCfg = Release|Any CPU
26 | {70CC82CC-9EFE-461F-A959-F64A06894621}.Release|Any CPU.Build.0 = Release|Any CPU
27 | {C5030463-0469-4AFA-92F4-F6B55A6B4C89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
28 | {C5030463-0469-4AFA-92F4-F6B55A6B4C89}.Debug|Any CPU.Build.0 = Debug|Any CPU
29 | {C5030463-0469-4AFA-92F4-F6B55A6B4C89}.Release|Any CPU.ActiveCfg = Release|Any CPU
30 | {C5030463-0469-4AFA-92F4-F6B55A6B4C89}.Release|Any CPU.Build.0 = Release|Any CPU
31 | EndGlobalSection
32 | GlobalSection(SolutionProperties) = preSolution
33 | HideSolutionNode = FALSE
34 | EndGlobalSection
35 | GlobalSection(NestedProjects) = preSolution
36 | {70CC82CC-9EFE-461F-A959-F64A06894621} = {F0EEB4AD-6E8F-47AC-BE12-98A0A15ABD95}
37 | {C5030463-0469-4AFA-92F4-F6B55A6B4C89} = {F0EEB4AD-6E8F-47AC-BE12-98A0A15ABD95}
38 | EndGlobalSection
39 | GlobalSection(ExtensibilityGlobals) = postSolution
40 | SolutionGuid = {E5C2784B-651F-471A-84F7-7A11969323CE}
41 | EndGlobalSection
42 | EndGlobal
43 |
--------------------------------------------------------------------------------
/source/Components/BusinessLib/BusinessLib.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {70CC82CC-9EFE-461F-A959-F64A06894621}
8 | Library
9 | Properties
10 | BusinessLib
11 | BusinessLib
12 | v4.5
13 | 512
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 | false
25 |
26 |
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 | false
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | Always
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/source/Components/BusinessLib/Models/MetaLocationModel.cs:
--------------------------------------------------------------------------------
1 | namespace BusinessLib.Models
2 | {
3 | using System.Collections.Generic;
4 | using System.Collections.ObjectModel;
5 | using System.Xml.Serialization;
6 |
7 | public class MetaLocationModel
8 | {
9 | #region fields
10 | private readonly ObservableCollection _Children = null;
11 | #endregion fields
12 |
13 | #region constructors
14 | ///
15 | /// Parameterized Class Constructor
16 | ///
17 | public MetaLocationModel(
18 | MetaLocationModel parent
19 | , int id
20 | , string iso
21 | , string localName
22 | , LocationType type
23 | , long in_Location
24 | , double geo_lat
25 | , double geo_lng
26 | , string db_id
27 | )
28 | : this()
29 | {
30 | Parent = parent;
31 |
32 | ID = id;
33 | ISO = iso;
34 | LocalName = localName;
35 | Type = type;
36 | In_Location = in_Location;
37 | Geo_lat = geo_lat;
38 | Geo_lng = geo_lng;
39 | DB_id = db_id;
40 | }
41 |
42 | ///
43 | /// Class Constructor
44 | ///
45 | public MetaLocationModel()
46 | {
47 | _Children = new ObservableCollection();
48 | }
49 | #endregion constructors
50 |
51 | #region properties
52 | [XmlIgnore]
53 | public MetaLocationModel Parent { get; private set; }
54 |
55 | public int ID { get; set; }
56 | public string ISO { get; set; }
57 | public string LocalName { get; set; }
58 | public LocationType Type { get; set; }
59 |
60 | public long In_Location { get; set; }
61 |
62 | public double Geo_lat { get; set; }
63 | public double Geo_lng { get; set; }
64 |
65 | public string DB_id { get; set; }
66 |
67 | [XmlIgnore]
68 | public IEnumerable Children
69 | {
70 | get
71 | {
72 | return _Children;
73 | }
74 | }
75 | #endregion properties
76 |
77 | #region methods
78 | public int ChildrenCount => _Children.Count;
79 |
80 | public void ChildrenAdd(MetaLocationModel child)
81 | {
82 | _Children.Add(child);
83 | }
84 |
85 | public void ChildrenRemove(MetaLocationModel child)
86 | {
87 | _Children.Remove(child);
88 | }
89 |
90 | public void ChildrenClear()
91 | {
92 | _Children.Clear();
93 | }
94 |
95 | public void SetParent(MetaLocationModel parent)
96 | {
97 | Parent = parent;
98 | }
99 | #endregion methods
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/source/FilterTreeView/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace FilterTreeView.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("FilterTreeView.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/ViewModels/Base/RelayCommand.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeViewLib.ViewModels.Base
2 | {
3 | using System;
4 | using System.Diagnostics;
5 | using System.Windows.Input;
6 |
7 | ///
8 | /// A class whose sole purpose is to relay its functionality to other
9 | /// objects by invoking delegates.
10 | ///
11 | /// The default return value for the CanExecute method is 'true'.
12 | ///
13 | /// Source: http://www.codeproject.com/Articles/31837/Creating-an-Internationalized-Wizard-in-WPF
14 | ///
15 | public class RelayCommand : ICommand
16 | {
17 | #region Fields
18 | private readonly Action mExecute = null;
19 | private readonly Predicate mCanExecute = null;
20 | #endregion // Fields
21 |
22 | #region Constructors
23 | ///
24 | /// Class constructor
25 | ///
26 | ///
27 | public RelayCommand(Action execute)
28 | : this(execute, null)
29 | {
30 | }
31 |
32 | ///
33 | /// Creates a new command.
34 | ///
35 | /// The execution logic.
36 | /// The execution status logic.
37 | public RelayCommand(Action execute, Predicate canExecute)
38 | {
39 | if (execute == null)
40 | throw new ArgumentNullException("execute");
41 |
42 | this.mExecute = execute;
43 | this.mCanExecute = canExecute;
44 | }
45 |
46 | #endregion // Constructors
47 |
48 | #region events
49 | ///
50 | /// Eventhandler to re-evaluate whether this command can execute or not
51 | ///
52 | public event EventHandler CanExecuteChanged
53 | {
54 | add
55 | {
56 | if (this.mCanExecute != null)
57 | CommandManager.RequerySuggested += value;
58 | }
59 |
60 | remove
61 | {
62 | if (this.mCanExecute != null)
63 | CommandManager.RequerySuggested -= value;
64 | }
65 | }
66 | #endregion
67 |
68 | #region methods
69 | ///
70 | /// Determine whether this pre-requisites to execute this command are given or not.
71 | ///
72 | ///
73 | ///
74 | [DebuggerStepThrough]
75 | public bool CanExecute(object parameter)
76 | {
77 | return this.mCanExecute == null ? true : this.mCanExecute((T)parameter);
78 | }
79 |
80 | ///
81 | /// Execute the command method managed in this class.
82 | ///
83 | ///
84 | public void Execute(object parameter)
85 | {
86 | this.mExecute((T)parameter);
87 | }
88 | #endregion methods
89 | }
90 | }
91 |
92 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/Behaviors/TreeViewItemExpanded.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeViewLib.Behaviors
2 | {
3 | using FilterTreeViewLib.Interfaces;
4 | using System.Windows;
5 | using System.Windows.Controls;
6 | using System.Windows.Input;
7 |
8 | ///
9 | /// Class implements an attached behaviour to bring a selected TreeViewItem
10 | /// into view when selection is driven by the viewmodel (not the user).
11 | ///
12 | public static class TreeViewItemExpanded
13 | {
14 | public static ICommand GetCommand(DependencyObject obj)
15 | {
16 | return (ICommand)obj.GetValue(CommandProperty);
17 | }
18 |
19 | public static void SetCommand(DependencyObject obj, ICommand value)
20 | {
21 | obj.SetValue(CommandProperty, value);
22 | }
23 |
24 | public static readonly DependencyProperty CommandProperty =
25 | DependencyProperty.RegisterAttached("Command",
26 | typeof(ICommand),
27 | typeof(TreeViewItemExpanded),
28 | new PropertyMetadata(null, OnPropertyChanged));
29 | #region methods
30 | private static void OnPropertyChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
31 | {
32 | TreeViewItem item = depObj as TreeViewItem;
33 | if (item == null)
34 | return;
35 |
36 | if (e.NewValue is ICommand == false)
37 | return;
38 |
39 | if ((ICommand)e.NewValue != null)
40 | {
41 | item.Expanded += Item_Expanded;
42 | }
43 | else
44 | {
45 | item.Expanded -= Item_Expanded;
46 | }
47 | }
48 |
49 | private static void Item_Expanded(object sender, RoutedEventArgs e)
50 | {
51 | var uiElement = sender as TreeViewItem;
52 |
53 | // Sanity check just in case this was somehow send by something else
54 | if (uiElement == null)
55 | return;
56 |
57 | IHasDummyChild f = null;
58 |
59 | if (uiElement.DataContext is IHasDummyChild)
60 | {
61 | f = uiElement.DataContext as IHasDummyChild;
62 |
63 | // Message Expand only for those who have 1 dummy folder below
64 | if (f.HasDummyChild == false)
65 | return;
66 | }
67 |
68 | ICommand changedCommand = TreeViewItemExpanded.GetCommand(uiElement);
69 |
70 | // There may not be a command bound to this after all
71 | if (changedCommand == null || f == null)
72 | return;
73 |
74 | // Check whether this attached behaviour is bound to a RoutedCommand
75 | if (changedCommand is RoutedCommand)
76 | {
77 | // Execute the routed command
78 | (changedCommand as RoutedCommand).Execute(f, uiElement);
79 | }
80 | else
81 | {
82 | // Execute the Command as bound delegate
83 | changedCommand.Execute(f);
84 | }
85 | }
86 | #endregion methods
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/ViewModels/Base/BaseViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeViewLib.ViewModels.Base
2 | {
3 | using System;
4 | using System.ComponentModel;
5 | using System.Linq.Expressions;
6 |
7 | ///
8 | /// Every ViewModel class is required to implement the INotifyPropertyChanged
9 | /// interface in order to tell WPF when a property changed (for instance, when
10 | /// a method or setter is executed).
11 | ///
12 | /// Therefore, the PropertyChanged methode has to be called when data changes,
13 | /// because the relevant properties may or may not be bound to GUI elements,
14 | /// which in turn have to refresh their display.
15 | ///
16 | /// The PropertyChanged method is to be called by the members and properties of
17 | /// the class that derives from this class. Each call contains the name of the
18 | /// property that has to be refreshed.
19 | ///
20 | /// The BaseViewModel is derived from from System.Windows.DependencyObject to allow
21 | /// resulting ViewModels the implemantion of dependency properties. Dependency properties
22 | /// in turn are useful when working with IValueConverter and ConverterParameters.
23 | ///
24 | public class BaseViewModel : INotifyPropertyChanged
25 | {
26 | ///
27 | /// Standard event handler of the interface
28 | ///
29 | public event PropertyChangedEventHandler PropertyChanged;
30 |
31 | ///
32 | /// Tell bound controls (via WPF binding) to refresh their display.
33 | ///
34 | /// Sample call: this.NotifyPropertyChanged(() => this.IsSelected);
35 | /// where 'this' is derived from
36 | /// and IsSelected is a property.
37 | ///
38 | ///
39 | ///
40 | public void NotifyPropertyChanged(Expression> property)
41 | {
42 | var lambda = (LambdaExpression)property;
43 | MemberExpression memberExpression;
44 |
45 | if (lambda.Body is UnaryExpression)
46 | {
47 | var unaryExpression = (UnaryExpression)lambda.Body;
48 | memberExpression = (MemberExpression)unaryExpression.Operand;
49 | }
50 | else
51 | memberExpression = (MemberExpression)lambda.Body;
52 |
53 | this.OnPropertyChanged(memberExpression.Member.Name);
54 | }
55 |
56 | ///
57 | /// Tell bound controls (via WPF binding) to refresh their display.
58 | ///
59 | /// Sample call: this.OnPropertyChanged("IsSelected");
60 | /// where 'this' is derived from
61 | /// and IsSelected is a property.
62 | ///
63 | /// Name of property to refresh
64 | public void OnPropertyChanged(string propertyName)
65 | {
66 | try
67 | {
68 | if (this.PropertyChanged != null)
69 | this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
70 | }
71 | catch
72 | {
73 | }
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/ViewModels/Tree/Search/SelectionRange.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeViewLib.ViewModels.Tree.Search
2 | {
3 | using System.Windows.Media;
4 | using FilterTreeViewLib.Interfaces;
5 |
6 | ///
7 | /// Implements a range object that can be used to indicate
8 | /// the start and end of a text selection or any other kind of range.
9 | ///
10 | public class SelectionRange : Base.BaseViewModel, ISelectionRange
11 | {
12 | #region fields
13 | private int _Start;
14 | private int _End;
15 | #endregion fields
16 |
17 | #region ctors
18 | ///
19 | /// Parameterized class constructor.
20 | ///
21 | ///
22 | ///
23 | public SelectionRange(int start, int end)
24 | : this()
25 | {
26 | Start = start;
27 | End = end;
28 | }
29 |
30 | ///
31 | /// Copy constructor
32 | ///
33 | ///
34 | public SelectionRange(SelectionRange copyThis)
35 | :this()
36 | {
37 | if (copyThis == null)
38 | return;
39 |
40 | Start = copyThis.Start;
41 | End = copyThis.End;
42 | SelectionBackground = copyThis.SelectionBackground;
43 | NormalBackground = copyThis.NormalBackground;
44 | DarkSkin = copyThis.DarkSkin;
45 | }
46 |
47 | ///
48 | /// Class constructor.
49 | ///
50 | public SelectionRange()
51 | {
52 | _Start = _End = 1;
53 | SelectionBackground = default(Color);
54 | NormalBackground = default(Color);
55 | DarkSkin = false;
56 | }
57 | #endregion ctors
58 |
59 | #region properties
60 | ///
61 | /// Gets the start of the indicated range.
62 | ///
63 | public int Start
64 | {
65 | get
66 | {
67 | return _Start;
68 | }
69 |
70 | private set
71 | {
72 | if (_Start != value)
73 | {
74 | _Start = value;
75 | NotifyPropertyChanged(() => Start);
76 | }
77 | }
78 | }
79 |
80 | ///
81 | /// Gets the end of the indicated range.
82 | ///
83 | public int End
84 | {
85 | get
86 | {
87 | return _End;
88 | }
89 |
90 | private set
91 | {
92 | if (_End != value)
93 | {
94 | _End = value;
95 | NotifyPropertyChanged(() => End);
96 | }
97 | }
98 | }
99 |
100 | ///
101 | /// Gets a bool value to determine whether DarkSkin default
102 | /// value for property should
103 | /// be applied or not.
104 | ///
105 | public bool DarkSkin { get; private set; }
106 |
107 | ///
108 | /// Gets the background color that is applied to the background brush,
109 | /// which should be applied when no match is indicated
110 | /// (this can be default(Color) in which case standard selection Brush
111 | /// is applied).
112 | ///
113 | public Color SelectionBackground { get; set; }
114 |
115 | ///
116 | /// Gets the background color that is applied to the background brush.
117 | /// which should be applied when no match is indicated
118 | /// (this can be default(Color) in which case Transparent is applied).
119 | ///
120 | public Color NormalBackground { get; set; }
121 |
122 | ///
123 | /// Gets a copy of this object.
124 | ///
125 | ///
126 | public object Clone()
127 | {
128 | return new SelectionRange(this);
129 | }
130 | #endregion properties
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/ViewModels/Tree/Search/SearchParams.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeViewLib.ViewModelsSearch.SearchModels
2 | {
3 | ///
4 | /// Implements a search object that contains the search string,
5 | /// related options, as well as methods to determine whether a
6 | /// given string is a match against the string or not.
7 | ///
8 | public class SearchParams
9 | {
10 | #region constructors
11 | ///
12 | /// Class constructor
13 | ///
14 | public SearchParams(
15 | string searchString
16 | , Enums.SearchMatch match)
17 | : this()
18 | {
19 | OriginalSearchString = SearchString = (searchString == null ? string.Empty : searchString);
20 | Match = match;
21 | }
22 |
23 | ///
24 | /// Class constructor
25 | ///
26 | public SearchParams()
27 | {
28 | SearchString = string.Empty;
29 | Match = Enums.SearchMatch.StringIsContained;
30 | MinimalSearchStringLength = 1;
31 | }
32 | #endregion constructors
33 |
34 | #region properties
35 | ///
36 | /// Gets the plain text string being searched or filtered.
37 | ///
38 | public string SearchString { get; private set; }
39 |
40 | ///
41 | /// Gets the plain text ORIGINAL string being searched or filtered.
42 | /// This string is the string that was set by the constructor and
43 | /// CANNOT be changed later on.
44 | ///
45 | public string OriginalSearchString { get; private set; }
46 |
47 | ///
48 | /// Gets the string being searched or filtered.
49 | ///
50 | public Enums.SearchMatch Match { get; private set; }
51 |
52 | ///
53 | /// Gets whether search string contains actual content or not.
54 | ///
55 | public bool IsSearchStringEmpty
56 | {
57 | get
58 | {
59 | return string.IsNullOrEmpty(SearchString);
60 | }
61 | }
62 |
63 | ///
64 | /// Gets the minimal search string length required.
65 | /// Any string shorter than this will not be searched at all.
66 | ///
67 | public int MinimalSearchStringLength { get; set; }
68 | #endregion properties
69 |
70 | #region methods
71 | ///
72 | /// Determines if a given string is considered a match in comparison
73 | /// to the search string and its options or not.
74 | ///
75 | ///
76 | /// true if is a match, otherwise false
77 | public int MatchSearchString(string stringToFind)
78 | {
79 | stringToFind = (stringToFind == null ? string.Empty : stringToFind);
80 |
81 | stringToFind = stringToFind.ToUpper();
82 |
83 | switch (Match)
84 | {
85 | case Enums.SearchMatch.StringIsContained:
86 | return stringToFind.IndexOf(SearchString);
87 |
88 | case Enums.SearchMatch.StringIsMatched:
89 | if (SearchString == stringToFind)
90 | return 0;
91 | break;
92 |
93 | default:
94 | throw new System.ArgumentOutOfRangeException(
95 | string.Format("Internal Error: Search option '{0}' not implemented.", Match));
96 | }
97 |
98 | return -1;
99 | }
100 |
101 | ///
102 | /// Can be called to trim the search string before matching takes place.
103 | ///
104 | public void SearchStringTrim()
105 | {
106 | SearchString = SearchString.Trim();
107 | }
108 |
109 | ///
110 | /// Can be called to convert the search string
111 | /// to upper case before matching takes place.
112 | ///
113 | public void SearchStringToUpperCase()
114 | {
115 | SearchString = SearchString.ToUpper();
116 | }
117 | #endregion methods
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/Behaviors/HighlightTextBlockBehavior.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeViewLib.Behaviors
2 | {
3 | using FilterTreeViewLib.Interfaces;
4 | using System.Windows;
5 | using System.Windows.Controls;
6 | using System.Windows.Documents;
7 | using System.Windows.Media;
8 | using System;
9 |
10 | ///
11 | /// Implements a behavior to highlight text as specified by
12 | /// a bound property that adheres to the interface.
13 | ///
14 | public static class HighlightTextBlockBehavior
15 | {
16 | #region fields
17 | ///
18 | /// Back Store of Attachable Dependency Property that indicates the range
19 | /// of text that should be highlighting (if any).
20 | ///
21 | private static readonly DependencyProperty RangeProperty =
22 | DependencyProperty.RegisterAttached("Range",
23 | typeof(ISelectionRange),
24 | typeof(HighlightTextBlockBehavior), new PropertyMetadata(null, OnRangeChanged));
25 | #endregion fields
26 |
27 | #region methods
28 | ///
29 | /// Gets the current values of the Range dependency property.
30 | ///
31 | public static ISelectionRange GetRange(DependencyObject obj)
32 | {
33 | return (ISelectionRange)obj.GetValue(RangeProperty);
34 | }
35 |
36 | ///
37 | /// Gets the current values of the Range dependency property.
38 | ///
39 | public static void SetRange(DependencyObject obj, ISelectionRange value)
40 | {
41 | obj.SetValue(RangeProperty, value);
42 | }
43 |
44 | ///
45 | /// Method executes whenever the Range dependency property valua has changed
46 | /// (in the bound viewmodel).
47 | ///
48 | ///
49 | ///
50 | private static void OnRangeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
51 | {
52 | TextBlock txtblock = d as TextBlock;
53 |
54 | if (txtblock == null)
55 | return;
56 |
57 | var range = GetRange(d); // Get the bound Range value to do highlighting
58 |
59 | // Standard background is transparent
60 | SolidColorBrush normalBackGround = new SolidColorBrush(Color.FromArgb(00, 00, 00, 00));
61 | if (range != null)
62 | {
63 | if (range.NormalBackground != default(Color))
64 | normalBackGround = new SolidColorBrush(range.NormalBackground);
65 | }
66 |
67 | // Reset Highlighting - this must be done anyways since
68 | // multiple selection runs will overlay each other
69 | var txtrange = new TextRange(txtblock.ContentStart, txtblock.ContentEnd);
70 | txtrange.ApplyPropertyValue(TextElement.BackgroundProperty, normalBackGround);
71 |
72 | if (range == null)
73 | return;
74 |
75 | if (range.Start < 0 || range.End < 0) // Nothing to highlight here :-(
76 | return;
77 |
78 | try
79 | {
80 | // Standard selection background color on dark skin: 254, 252, 200
81 | // Standard selection background color on light skin: 208, 247, 255
82 | Color selColor = (range.DarkSkin ? Color.FromArgb(255, 254, 252, 200) :
83 | Color.FromArgb(255, 208, 247, 255));
84 |
85 | Brush selectionBackground = new SolidColorBrush(selColor);
86 | if (range != null)
87 | {
88 | if (range.SelectionBackground != default(Color))
89 | selectionBackground = new SolidColorBrush(range.SelectionBackground);
90 | }
91 |
92 | TextRange txtrangel = new TextRange(
93 | txtblock.ContentStart.GetPositionAtOffset(range.Start + 1)
94 | , txtblock.ContentStart.GetPositionAtOffset(range.End + 1));
95 |
96 | txtrangel.ApplyPropertyValue(TextElement.BackgroundProperty, selectionBackground);
97 | }
98 | catch (Exception exc)
99 | {
100 | Console.WriteLine(exc.Message);
101 | Console.WriteLine(exc.StackTrace);
102 | }
103 | }
104 | #endregion methods
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/ViewModels/Tree/Search/StringMatchItem.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeViewLib.ViewModels.Tree.Search
2 | {
3 | using FilterTreeViewLib.Interfaces;
4 |
5 | ///
6 | /// Implements a viewmodel that provides a string to display and can indicate
7 | /// a macthing range against another string via the property.
8 | ///
9 | public class StringMatchItem : Base.BaseViewModel
10 | {
11 | #region fields
12 | private ISelectionRange _Range;
13 | private string _DisplayString;
14 | #endregion fields
15 |
16 | #region ctors
17 | ///
18 | /// Parameterized class constructor.
19 | ///
20 | ///
21 | public StringMatchItem(string displayString)
22 | {
23 | DisplayString = displayString;
24 | }
25 |
26 | ///
27 | /// Class constructor.
28 | ///
29 | public StringMatchItem()
30 | {
31 | _Range = new SelectionRange();
32 | _DisplayString = string.Empty;
33 | }
34 | #endregion ctors
35 |
36 | #region properties
37 | ///
38 | /// Gets the range property that indicates the text range
39 | /// to be considered a match against another (search) string.
40 | ///
41 | public ISelectionRange Range
42 | {
43 | get
44 | {
45 | return _Range;
46 | }
47 |
48 | private set
49 | {
50 | if (_Range != null && value != null)
51 | {
52 | // Nothing changed - so we change nothing here :-)
53 | if (_Range.Start == value.Start &&
54 | _Range.End == value.End)
55 | return;
56 |
57 | _Range = value;
58 | NotifyPropertyChanged(() => Range);
59 | }
60 |
61 | if (_Range == null && value != null ||
62 | _Range != null && value == null)
63 | {
64 | _Range = value;
65 | NotifyPropertyChanged(() => Range);
66 | }
67 | }
68 | }
69 |
70 | ///
71 | /// Gets te string that should be displayed (with or without hightlighting)
72 | ///
73 | public string DisplayString
74 | {
75 | get
76 | {
77 | return _DisplayString;
78 | }
79 |
80 | private set
81 | {
82 | if (_DisplayString != value)
83 | {
84 | _DisplayString = value;
85 | NotifyPropertyChanged(() => DisplayString);
86 | }
87 | }
88 | }
89 | #endregion properties
90 |
91 | #region methods
92 | ///
93 | /// Evaluates the given string against the
94 | /// property and sets the property to indicate the
95 | /// matched text range.
96 | ///
97 | ///
98 | ///
99 | public bool MatchString(string searchString)
100 | {
101 | if (string.IsNullOrEmpty(DisplayString) == true &&
102 | string.IsNullOrEmpty(searchString) == true)
103 | {
104 | Range = new SelectionRange(0, 0);
105 | return true;
106 | }
107 | else
108 | {
109 | // There is no point in making this a match
110 | // if only one of the strings is not present
111 | if (string.IsNullOrEmpty(DisplayString) == true ||
112 | string.IsNullOrEmpty(searchString) == true)
113 | {
114 | Range = new SelectionRange(-1, -1);
115 | return false;
116 | }
117 | }
118 |
119 | // Do we have a (sub)match or not ???
120 | int start;
121 | if ((start = DisplayString.IndexOf(searchString)) >= 0)
122 | {
123 | Range = new SelectionRange(start, start + searchString.Length);
124 | return true;
125 | }
126 | else
127 | {
128 | Range = new SelectionRange(start, -1);
129 | return false;
130 | }
131 | }
132 | #endregion methods
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/ViewModels/AppBaseViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeViewLib.ViewModels
2 | {
3 | using System.Threading.Tasks;
4 |
5 | public abstract class AppBaseViewModel : Base.BaseViewModel
6 | {
7 | #region fields
8 | private bool _IsStringContainedSearchOption;
9 | private int _CountSearchMatches;
10 | private bool _IsProcessing;
11 | private bool _IsLoading;
12 |
13 | private string _StatusStringResult;
14 | private string _SearchString;
15 | #endregion fields
16 |
17 | #region constructors
18 | ///
19 | /// Class constructor
20 | ///
21 | public AppBaseViewModel()
22 | {
23 | _SearchString = "Washington";
24 | _IsProcessing = _IsLoading = false;
25 | _CountSearchMatches = 0;
26 | _IsStringContainedSearchOption = true;
27 | }
28 | #endregion constructors
29 |
30 | #region properties
31 | ///
32 | /// Gets a property to determine if application is currently processing
33 | /// data (loading or searching for matches in the tree view) or not.
34 | ///
35 | public bool IsProcessing
36 | {
37 | get { return _IsProcessing; }
38 | protected set
39 | {
40 | if (_IsProcessing != value)
41 | {
42 | _IsProcessing = value;
43 | NotifyPropertyChanged(() => IsProcessing);
44 | }
45 | }
46 | }
47 |
48 | ///
49 | /// Gets a property to determine if application is currently processing
50 | /// data (loading or searching for matches in the tree view) or not.
51 | ///
52 | public bool IsLoading
53 | {
54 | get { return _IsLoading; }
55 | protected set
56 | {
57 | if (_IsLoading != value)
58 | {
59 | _IsLoading = value;
60 | NotifyPropertyChanged(() => IsLoading);
61 | }
62 | }
63 | }
64 |
65 | ///
66 | /// Gets the input string from search textbox control.
67 | ///
68 | public string SearchString
69 | {
70 | get { return _SearchString; }
71 | set
72 | {
73 | if (_SearchString != value)
74 | {
75 | _SearchString = value;
76 | NotifyPropertyChanged(() => SearchString);
77 | }
78 | }
79 | }
80 |
81 | ///
82 | /// Gets the search string that is synchronized with the results from the search algorithm.
83 | ///
84 | public string StatusStringResult
85 | {
86 | get { return _StatusStringResult; }
87 | protected set
88 | {
89 | if (_StatusStringResult != value)
90 | {
91 | _StatusStringResult = value;
92 | NotifyPropertyChanged(() => StatusStringResult);
93 | }
94 | }
95 | }
96 |
97 | ///
98 | /// Determines whether the search is looking for:
99 | /// - strings that are contained in a given string or
100 | /// - strings that match the searched string with all letters.
101 | ///
102 | public bool IsStringContainedSearchOption
103 | {
104 | get { return _IsStringContainedSearchOption; }
105 | set
106 | {
107 | if (_IsStringContainedSearchOption != value)
108 | {
109 | _IsStringContainedSearchOption = value;
110 | NotifyPropertyChanged(() => IsStringContainedSearchOption);
111 | }
112 | }
113 | }
114 |
115 | ///
116 | /// Gets the number of matches that are found durring
117 | /// a search in the tree view nodes for a given string.
118 | ///
119 | public int CountSearchMatches
120 | {
121 | get { return _CountSearchMatches; }
122 | protected set
123 | {
124 | if (_CountSearchMatches != value)
125 | {
126 | _CountSearchMatches = value;
127 | NotifyPropertyChanged(() => CountSearchMatches);
128 | }
129 | }
130 | }
131 | #endregion properties
132 |
133 | #region methods
134 | ///
135 | /// Loads the initial sample data from XML file into memory
136 | ///
137 | ///
138 | public abstract Task LoadSampleDataAsync();
139 | #endregion methods
140 | }
141 | }
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/FilterTreeViewLib.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {C5030463-0469-4AFA-92F4-F6B55A6B4C89}
8 | Library
9 | Properties
10 | FilterTreeViewLib
11 | FilterTreeViewLib
12 | v4.5
13 | 512
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | TRACE;DEBUG;TREELIB
22 | prompt
23 | 4
24 | false
25 |
26 |
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE;TREELIB
31 | prompt
32 | 4
33 | false
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | ..\..\packages\Dirkster.TreeLib.1.2.0\lib\net40\TreeLib.dll
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 | {70cc82cc-9efe-461f-a959-f64a06894621}
99 | BusinessLib
100 |
101 |
102 |
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/source/Components/FilterTreeViewLib/Behaviors/TextChangedCommand.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeViewLib.Behaviors
2 | {
3 | using System.Windows;
4 | using System.Windows.Controls;
5 | using System.Windows.Input;
6 |
7 | ///
8 | /// Source:
9 | /// http://stackoverflow.com/questions/1034374/drag-and-drop-in-mvvm-with-scatterview
10 | /// http://social.msdn.microsoft.com/Forums/de-DE/wpf/thread/21bed380-c485-44fb-8741-f9245524d0ae
11 | ///
12 | /// Attached behaviour to implement the drop event via delegate command binding or routed commands.
13 | ///
14 | public static class TextChangedCommand
15 | {
16 | // Field of attached ICommand property
17 | private static readonly DependencyProperty ChangedCommandProperty = DependencyProperty.RegisterAttached(
18 | "ChangedCommand",
19 | typeof(ICommand),
20 | typeof(TextChangedCommand),
21 | new PropertyMetadata(null, OnTextChangedCommandChange));
22 |
23 | ///
24 | /// Setter method of the attached DropCommand property
25 | ///
26 | ///
27 | ///
28 | public static void SetChangedCommand(DependencyObject source, ICommand value)
29 | {
30 | source.SetValue(ChangedCommandProperty, value);
31 | }
32 |
33 | ///
34 | /// Getter method of the attached DropCommand property
35 | ///
36 | ///
37 | ///
38 | public static ICommand GetChangedCommand(DependencyObject source)
39 | {
40 | return (ICommand)source.GetValue(ChangedCommandProperty);
41 | }
42 |
43 | ///
44 | /// This method is hooked in the definition of the .
45 | /// It is called whenever the attached property changes - in our case the event of binding
46 | /// and unbinding the property to a sink is what we are looking for.
47 | ///
48 | ///
49 | ///
50 | private static void OnTextChangedCommandChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
51 | {
52 | TextBox uiElement = d as TextBox; // Remove the handler if it exist to avoid memory leaks
53 |
54 | if (uiElement != null)
55 | {
56 | uiElement.TextChanged -= OnText_Changed;
57 |
58 | var command = e.NewValue as ICommand;
59 | if (command != null)
60 | {
61 | // the property is attached so we attach the Drop event handler
62 | uiElement.TextChanged += OnText_Changed;
63 | }
64 | }
65 | }
66 |
67 | ///
68 | /// This method is called when the TextChanged event occurs. The sender should be the control
69 | /// on which this behaviour is attached - so we convert the sender into a
70 | /// and receive the Command through the GetDropCommand getter listed above.
71 | ///
72 | /// The parameter contains the standard data,
73 | /// which is unpacked and realesed upon the bound command.
74 | ///
75 | /// This implementation supports binding of delegate commands and routed commands.
76 | ///
77 | ///
78 | ///
79 | private static void OnText_Changed(object sender, TextChangedEventArgs e)
80 | {
81 | TextBox uiElement = sender as TextBox;
82 |
83 |
84 | // Sanity check just in case this was somehow send by something else
85 | if (uiElement == null)
86 | return;
87 |
88 | // Bugfix: A change during disabled state is likely to be caused by a bound property
89 | // in a viewmodel (a machine based edit rather than user input)
90 | // -> Lets break the message loop here to avoid unnecessary CPU processings...
91 | if (uiElement.IsEnabled == false)
92 | return;
93 |
94 | ICommand changedCommand = TextChangedCommand.GetChangedCommand(uiElement);
95 |
96 | // There may not be a command bound to this after all
97 | if (changedCommand == null)
98 | return;
99 |
100 | var item = uiElement.Text;
101 |
102 | // Check whether this attached behaviour is bound to a RoutedCommand
103 | if (changedCommand is RoutedCommand)
104 | {
105 | // Execute the routed command
106 | (changedCommand as RoutedCommand).Execute(item, uiElement);
107 | }
108 | else
109 | {
110 | // Execute the Command as bound delegate
111 | changedCommand.Execute(item);
112 | }
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/source/FilterTreeView/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/source/FilterTreeView/FilterTreeView.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {9668A53D-608F-46B1-926C-14AC52CD35AE}
8 | WinExe
9 | Properties
10 | FilterTreeView
11 | FilterTreeView
12 | v4.5.2
13 | 512
14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
15 | 4
16 | true
17 |
18 |
19 |
20 |
21 | AnyCPU
22 | true
23 | full
24 | false
25 | bin\Debug\
26 | TRACE;DEBUG;TREELIB
27 | prompt
28 | 4
29 | false
30 |
31 |
32 | AnyCPU
33 | pdbonly
34 | true
35 | bin\Release\
36 | TRACE
37 | prompt
38 | 4
39 | false
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | 4.0
57 |
58 |
59 | ..\packages\Dirkster.TreeLib.1.2.0\lib\net40\TreeLib.dll
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | MSBuild:Compile
68 | Designer
69 |
70 |
71 |
72 |
73 |
74 | MSBuild:Compile
75 | Designer
76 |
77 |
78 | App.xaml
79 | Code
80 |
81 |
82 | MainWindow.xaml
83 | Code
84 |
85 |
86 |
87 |
88 | Code
89 |
90 |
91 | True
92 | True
93 | Resources.resx
94 |
95 |
96 | True
97 | Settings.settings
98 | True
99 |
100 |
101 | ResXFileCodeGenerator
102 | Resources.Designer.cs
103 |
104 |
105 |
106 | SettingsSingleFileGenerator
107 | Settings.Designer.cs
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 | {70cc82cc-9efe-461f-a959-f64a06894621}
117 | BusinessLib
118 |
119 |
120 | {c5030463-0469-4afa-92f4-f6b55a6b4c89}
121 | FilterTreeViewLib
122 |
123 |
124 |
125 |
132 |
--------------------------------------------------------------------------------
/source/FilterTreeView/ViewModels/AppViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace FilterTreeView.ViewModels
2 | {
3 | using FilterTreeView.Tasks;
4 | using FilterTreeViewLib.ViewModels;
5 | using FilterTreeViewLib.ViewModels.Base;
6 | using FilterTreeViewLib.ViewModelsSearch.SearchModels;
7 | using FilterTreeViewLib.ViewModelsSearch.SearchModels.Enums;
8 | using System;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 | using System.Windows.Input;
12 |
13 | ///
14 | /// Implements the application viewmodel object that manages all main commands
15 | /// and bindings visible in the main window.
16 | ///
17 | internal class AppViewModel : FilterTreeViewLib.ViewModels.AppBaseViewModel, IDisposable
18 | {
19 | #region fields
20 | private readonly OneTaskProcessor _procesor;
21 |
22 | private readonly MetaLocationRootViewModel _Root;
23 |
24 | private ICommand _SearchCommand;
25 | private bool _Disposed;
26 | #endregion fields
27 |
28 | #region constructors
29 | ///
30 | /// Class constructor
31 | ///
32 | public AppViewModel()
33 | : base()
34 | {
35 | _procesor = new OneTaskProcessor();
36 | _Root = new MetaLocationRootViewModel();
37 | _Disposed = false;
38 | }
39 | #endregion constructors
40 |
41 | #region properties
42 | ///
43 | /// Gets the root viewmodel that can be bound to a treeview control.
44 | ///
45 | public MetaLocationRootViewModel Root
46 | {
47 | get
48 | {
49 | return _Root;
50 | }
51 | }
52 |
53 | ///
54 | /// Gets a command that filters the display of nodes in a treeview
55 | /// with a filterstring (node is shown if filterstring is contained).
56 | ///
57 | public ICommand SearchCommand
58 | {
59 | get
60 | {
61 | if (_SearchCommand == null)
62 | {
63 | _SearchCommand = new RelayCommand