diff --git a/BeWo/View/Controls/TextModuleTreeViewControl.xaml b/BeWo/View/Controls/TextModuleTreeViewControl.xaml
new file mode 100644
index 000000000..69be5dfef
--- /dev/null
+++ b/BeWo/View/Controls/TextModuleTreeViewControl.xaml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BeWo/View/Controls/TextModuleTreeViewControl.xaml.cs b/BeWo/View/Controls/TextModuleTreeViewControl.xaml.cs
new file mode 100644
index 000000000..e653d4ab8
--- /dev/null
+++ b/BeWo/View/Controls/TextModuleTreeViewControl.xaml.cs
@@ -0,0 +1,125 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Controls.Primitives;
+using System.Windows.Input;
+
+using BeWo.Annotations;
+using BeWo.ViewModel;
+
+using BS.Shared.Core;
+using BS.Shared.Extensions;
+
+
+namespace BeWo.View.Controls
+{
+ public partial class TextModuleTreeViewControl : INotifyPropertyChanged
+ {
+ public event EventHandler> TextModuleSelected;
+
+ public TextModuleTreeViewControl()
+ {
+ InitializeComponent();
+ DataContext = this;
+ }
+
+ public long? ServiceCategoryOid { get; set; }
+
+ private List allTextModules = new List();
+
+ public BindingList FilteredList { get; set; }
+
+ private void OpenPopUpBtnClick(object sender, RoutedEventArgs e)
+ {
+ VMFactory.CreateTextModuleListVMAsync(
+ textModules => this.Dispatch(delegate
+ {
+ TreeViewPopup.Placement = PlacementMode.RelativePoint;
+ TreeViewPopup.HorizontalOffset = 0;
+ TreeViewPopup.IsOpen = true;
+
+ allTextModules = textModules.VMList.ToList();
+
+ if(ServiceCategoryOid != null)
+ {
+ FilteredList = new BindingList();
+
+ var preFilteredTextModules = textModules.VMList.Where(w => w.ServiceCategory != null && w.ServiceCategory.ServiceCategoryOid == ServiceCategoryOid || w.ServiceCategory == null && !w.IsParent).ToList();
+
+ FilteredList.AddRange(preFilteredTextModules);
+ SearchTextModulesRecursively(preFilteredTextModules);
+ }
+ else
+ {
+ FilteredList = new BindingList(textModules.VMList);
+ }
+
+ allTextModules = FilteredList.ToList();
+ OnPropertyChanged(nameof(FilteredList));
+ }));
+ }
+
+ private void TreeListControl_OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
+ {
+ var selectedTextModule = (TextModuleVM) TreeListControl.SelectedItem;
+
+ if(selectedTextModule.IsParent)
+ {
+ return;
+ }
+
+ TreeViewPopup.IsOpen = false;
+
+ TextModuleSelected?.Invoke(this, new EventArgs(selectedTextModule));
+ }
+
+ private void SearchTextBox_OnTextChanged(object sender, TextChangedEventArgs e)
+ {
+ var searchText = ((TextBox) sender).Text.Trim();
+ FilteredList.Clear();
+
+ if(searchText.IsNullOrEmpty())
+ {
+ FilteredList = new BindingList(allTextModules.ToList());
+ }
+ else
+ {
+ var matchingChildren = allTextModules.Where(w => w.Name.Contains(searchText) || w.Text != null && w.Text.Contains(searchText)).ToList();
+
+ FilteredList.AddRange(matchingChildren);
+ SearchTextModulesRecursively(matchingChildren);
+ }
+
+ OnPropertyChanged(nameof(FilteredList));
+ TreeListControl.RefreshData();
+ }
+
+ private void SearchTextModulesRecursively(IReadOnlyCollection pChildren)
+ {
+ if(pChildren.Count == 0)
+ {
+ return;
+ }
+
+ foreach(var child in pChildren)
+ {
+ var parents = allTextModules.Where(w => Equals(child.Parent, w) && !FilteredList.Contains(w)).ToList();
+
+ FilteredList.AddRange(parents);
+ SearchTextModulesRecursively(parents);
+ }
+ }
+
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ [NotifyPropertyChangedInvocator]
+ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+ }
+}