Hi,
ich hab gerade ein Problemchen bei dem ich mir, selbst nach einiger Zeit googlen, die Zähne ausbeiße.
Ich hab ein TreeView welches mir alle Unterordner und Dateien in einem vorgegeben Pfad auflistet, soweit so gut.
Bei Klick auf eine Datei wird diese in einem TabPage geöffnet, passt auch.
Nun hab ich in den Settings ein Propertie
Das funktioniert alles bestens, doch wie kann ich nun dem TreeView verklickern, das es bis zu diesem Selected Item expanden soll? (die IsSelected und IsExpanden Properties sind im DirectoryItemViewModel.
Ich nutze folgende ViewModels:
Das MainViewModel mit dem Selected Item:
MainViewModel
Das DirectoryItemViewModel für ein einzelnes Item:
DirectoryItemViewModel
dann nmoch die entsprechende Stelle im TreeView:
TreeView Xaml
Nicht wundern in den ViewModels, ich nutze hier noch das nuget Packet Fody, das bin ich gerade am Ändern.
Was ich bisher gelesen habe, sollte das TreeView selbst expanden, wenn IsSelected gesetzt wird.
Die Lösungen im Netz sind entweder CodeBehind, Behaiviors, oder Dependency Properties.
Aber das müsste doch in WPF einfacher gehen, oder?
Danke Euch
ich hab gerade ein Problemchen bei dem ich mir, selbst nach einiger Zeit googlen, die Zähne ausbeiße.
Ich hab ein TreeView welches mir alle Unterordner und Dateien in einem vorgegeben Pfad auflistet, soweit so gut.
Bei Klick auf eine Datei wird diese in einem TabPage geöffnet, passt auch.
Nun hab ich in den Settings ein Propertie
LastOpenFile
im MainViewModel weise ich dem SelectedItem den Pfad aus LastOpenFile zu und öffne die Datei im entsprechenden TabPage (siehe ReloadDate() ab Zeile 194.Das funktioniert alles bestens, doch wie kann ich nun dem TreeView verklickern, das es bis zu diesem Selected Item expanden soll? (die IsSelected und IsExpanden Properties sind im DirectoryItemViewModel.
Ich nutze folgende ViewModels:
Das MainViewModel mit dem Selected Item:
C#-Quellcode
- public class MainViewModel : ViewModelBase
- {
- #region Private Properties
- private string _path => IoC.Application.CodeFolderPath;
- #endregion
- #region Constructor
- public MainViewModel()
- {
- if (!string.IsNullOrEmpty(_path))
- {
- ReloadData();
- ClearTabPages();
- InitCommands();
- }
- }
- #endregion
- #region Public Properties
- public ObservableCollection<DirectoryItemViewModel> DirectoryItems { get; set; }
- public DirectoryItemViewModel SelectedItem { get; set; }
- public ObservableCollection<TabPageViewModel> TabPages { get; set; }
- public TabPageViewModel SelectedTab { get; set; }
- public string RootFolderName => _path.GetFileFolderName();
- public bool CanCloseAllTabPages => TabPages.Count > 0;
- public bool CanAddNewFileOrFolder => SelectedItem != null && SelectedItem.Type == DirectoryItemTypeEnum.Folder;
- public bool CanSave => FileFolderName.Length > 0;
- public bool HasItems => DirectoryItems.Count > 0;
- public bool OnCreate { get; set; }
- public string TextEntryLabel { get; set; }
- public string FileFolderName { get; set; } = string.Empty;
- #endregion
- #region Events
- private void DirectoryItems_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
- {
- OnPropertyChanged(nameof(CanAddNewFileOrFolder));
- OnPropertyChanged(nameof(HasItems));
- }
- private void TabPages_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
- {
- OnPropertyChanged(nameof(CanCloseAllTabPages));
- }
- #endregion
- #region Commands
- public ICommand OpenFileCommand { get; set; }
- public ICommand CloseTabCommand { get; set; }
- public ICommand CloseAllTabsCommand { get; set; }
- public ICommand AddNewFileCommand { get; set; }
- public ICommand AddNewFolderCommand { get; set; }
- public ICommand ExpandAndCollapsAllCommand { get; set; }
- public ICommand OpenRootFolderCommand { get; set; }
- public ICommand SaveFileOrFolderCommand { get; set; }
- public ICommand CancelFileOrFolderCommand { get; set; }
- #endregion
- #region Comamnd Methods
- private void OpenFile(object param)
- {
- SelectedItem = param as DirectoryItemViewModel;
- if (SelectedItem.Type != DirectoryItemTypeEnum.File) return;
- TabPageViewModel existingTab = TabPages.Where(x => x.Tag == SelectedItem.FullPath).FirstOrDefault();
- if (existingTab != null)
- SelectedTab = existingTab;
- else
- {
- var newTab = new TabPageViewModel(SelectedItem.Name, SelectedItem.FullPath,
- new EditorViewModel (SelectedItem.FullPath));
- TabPages.Add(newTab);
- SelectedTab = newTab;
- }
- SelectedItem.IsSelected = true;
- }
- private void CloseTab(object param)
- {
- var tabToClose = param as TabPageViewModel;
- if(tabToClose.Editor.IsModified)
- {
- //TODO: Über IoC MessageBox aufrufen und dort das Speichern abfragen
- DirectoryStructure.SaveContent(tabToClose.Tag, tabToClose.Editor.Content);
- }
- TabPages.Remove(tabToClose);
- if (TabPages.Count <= 0)
- ClearTabPages();
- }
- private void AddNewFileOrFolder(string arg)
- {
- if (SelectedItem != null && SelectedItem.Type == DirectoryItemTypeEnum.Folder)
- {
- if (arg == "Neue Datei")
- {
- var newFile = new DirectoryItemViewModel(SelectedItem.FullPath + @"\" + FileFolderName, DirectoryItemTypeEnum.File);
- SelectedItem.ChildItems.Add(newFile);
- var newTab = new TabPageViewModel(newFile.Name, newFile.FullPath,
- new EditorViewModel("Code goes here", newFile.FullPath) { IsModified = true });
- DirectoryStructure.SaveContent(newTab.Tag, newTab.Editor.Content);
- TabPages.Add(newTab);
- SelectedTab = newTab;
- }
- else
- {
- DirectoryStructure.CreateDirectories(SelectedItem.FullPath + @"\" + FileFolderName);
- ReloadData();
- }
- }
- FileFolderName = string.Empty;
- OnCreate = false;
- }
- private void CloseAllTabPages()
- {
- if(TabPages.Any(t => t.Editor.IsModified))
- {
- //TODO: Messagebox zum speichern
- }
- ClearTabPages();
- }
- private void ExpandAndCollapsAll()
- {
- foreach (var item in DirectoryItems)
- {
- if (item.Type == DirectoryItemTypeEnum.Folder)
- item.IsExpanded ^= true;
- }
- }
- public void OpenRootFolder()
- {
- //TODO: FolderBrowserDialog aufrufen
- CloseAllTabPages();
- ReloadData();
- OnPropertyChanged(nameof(RootFolderName));
- }
- private void Edit(string label)
- {
- TextEntryLabel = label;
- OnCreate = true;
- }
- private void Cancel()
- {
- FileFolderName = string.Empty;
- OnCreate = false;
- }
- #endregion
- #region Helper Methods
- private void ClearTabPages()
- {
- TabPages = new ObservableCollection<TabPageViewModel>();
- TabPages.CollectionChanged += TabPages_CollectionChanged;
- }
- private void ReloadData()
- {
- DirectoryItems = new ObservableCollection<DirectoryItemViewModel>(_path.GetFilesFolders().Select(f => new DirectoryItemViewModel(f.FullPath, f.Type)));
- DirectoryItems.CollectionChanged += DirectoryItems_CollectionChanged;
- SelectedItem = new DirectoryItemViewModel(IoC.Settings.LastOpenFile, DirectoryItemTypeEnum.File);
- SelectedItem.IsSelected = true;
- SelectedTab = new TabPageViewModel(SelectedItem.Name, SelectedItem.FullPath, new EditorViewModel(SelectedItem.FullPath));
- TabPages.Add(SelectedTab);
- }
- private void InitCommands()
- {
- OpenFileCommand = new RelayCommand(o => OpenFile(o));
- CloseTabCommand = new RelayCommand(c => CloseTab(c));
- CloseAllTabsCommand = new RelayCommand(c => CloseAllTabPages()).ObservesCanExecute(() => CanCloseAllTabPages);
- AddNewFileCommand = new RelayCommand(a => Edit("Neue Datei")).ObservesCanExecute(() => CanAddNewFileOrFolder);
- AddNewFolderCommand = new RelayCommand(a => Edit("Neuer Ordner")).ObservesCanExecute(() => CanAddNewFileOrFolder);
- ExpandAndCollapsAllCommand = new RelayCommand(e => ExpandAndCollapsAll());
- OpenRootFolderCommand = new RelayCommand(o => OpenRootFolder());
- SaveFileOrFolderCommand = new RelayCommand(s => AddNewFileOrFolder(TextEntryLabel)).ObservesCanExecute(() => CanSave);
- CancelFileOrFolderCommand = new RelayCommand(c =>Cancel());
- }
- #endregion
- }
Das DirectoryItemViewModel für ein einzelnes Item:
C#-Quellcode
- public class DirectoryItemViewModel : ViewModelBase
- {
- #region Constructor
- /// <summary>
- /// default constructor
- /// </summary>
- public DirectoryItemViewModel()
- {
- }
- public DirectoryItemViewModel(string fullpath, DirectoryItemTypeEnum type)
- {
- FullPath = fullpath;
- Type = type;
- ClearDirectoryItems();
- InitCommands();
- }
- #endregion
- #region Public Properties
- #region Model Properties
- public string FullPath { get; set; }
- public string Name => Type == DirectoryItemTypeEnum.Drive ? FullPath : FullPath.GetFileFolderName();
- public DirectoryItemTypeEnum Type { get; set; }
- #endregion
- #region UI Properties
- public string ImageName => Type == DirectoryItemTypeEnum.Drive ? "drive" : (Type == DirectoryItemTypeEnum.File ? "file" : (IsExpanded ? "folder-open" : "folder-close"));
- public ObservableCollection<DirectoryItemViewModel> ChildItems { get; set; }
- public bool CanOpen => Type == DirectoryItemTypeEnum.File;
- public bool CanExpand => Type != DirectoryItemTypeEnum.File;
- public bool IsSelected { get; set; }
- public bool IsExpanded
- {
- get => ChildItems?.Count(i => i != null) > 0;
- set
- {
- if (value == true)
- Expand();
- else
- ClearDirectoryItems();
- }
- }
- #endregion
- #endregion
- #region Commands
- public ICommand ExpandCommand { get; set; }
- #endregion
- #region Command Methods
- private void Expand()
- {
- if (Type == DirectoryItemTypeEnum.File)
- return;
- ChildItems = new ObservableCollection<DirectoryItemViewModel>(FullPath.GetFilesFolders().Select(item => new DirectoryItemViewModel(item.FullPath, item.Type)));
- }
- #endregion
- #region Helper Methods
- private void InitCommands()
- {
- ExpandCommand = new RelayCommand(e => Expand());
- }
- private void ClearDirectoryItems()
- {
- ChildItems = new ObservableCollection<DirectoryItemViewModel>();
- if (Type != DirectoryItemTypeEnum.File)
- ChildItems.Add(null);
- }
- #endregion
- }
dann nmoch die entsprechende Stelle im TreeView:
XML-Quellcode
- <!-- #region TreeView (Row 1) -->
- <TreeView x:Name="tv" ItemsSource="{Binding DirectoryItems}" Grid.Row="2" BorderThickness="0" Background="{StaticResource BackgroundVeryLightBrush}">
- <TreeView.Resources>
- <LinearGradientBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" EndPoint="0,1" StartPoint="0,0">
- <GradientStop Color="{StaticResource DefaultLightDark}" Offset="0"/>
- <GradientStop Color="{StaticResource DefaultLight}" Offset="1"/>
- </LinearGradientBrush>
- <LinearGradientBrush x:Key="{x:Static SystemColors.ControlBrushKey}" EndPoint="0,1" StartPoint="0,0">
- <GradientStop Color="#FFF8F8F8" Offset="0"/>
- <GradientStop Color="#FFE5E5E5" Offset="1"/>
- </LinearGradientBrush>
- <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
- <SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Black" />
- </TreeView.Resources>
- <TreeView.ItemContainerStyle>
- <Style TargetType="{x:Type TreeViewItem}">
- <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
- <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
- <Style.Triggers>
- <Trigger Property="IsSelected" Value="True">
- <Setter Property="Background" Value="{StaticResource BackgroundGradientBrush}"/>
- </Trigger>
- <Trigger Property="IsMouseOver" Value="True">
- <Setter Property="Background" Value="{StaticResource BackgroundGradientBrush}"/>
- </Trigger>
- </Style.Triggers>
- <Style.Resources>
- <Style TargetType="{x:Type Border}">
- <Setter Property="CornerRadius" Value="2"/>
- </Style>
- </Style.Resources>
- </Style>
- </TreeView.ItemContainerStyle>
- <TreeView.ItemTemplate>
- <HierarchicalDataTemplate ItemsSource="{Binding ChildItems}">
- <StackPanel Orientation="Horizontal" Margin="5 0 10 0">
- <Image Width="20" Margin="3" Source="{Binding ImageName, Converter={local:HeaderTextToImageConverter}}"/>
- <TextBlock Text="{Binding Name, UpdateSourceTrigger=LostFocus}"
- VerticalAlignment="Center"
- Foreground="{StaticResource CharDarkBlueBrush}"
- FontSize="{StaticResource FontSizeRegular}"
- Background="Transparent"
- Padding="2" >
- <TextBlock.InputBindings>
- <MouseBinding MouseAction="LeftClick" Command="{Binding DataContext.OpenFileCommand, ElementName=mainUc}" CommandParameter="{Binding}"/>
- </TextBlock.InputBindings>
- </TextBlock>
- </StackPanel>
- </HierarchicalDataTemplate>
- </TreeView.ItemTemplate>
- </TreeView>
- <!-- #endregion -->
Nicht wundern in den ViewModels, ich nutze hier noch das nuget Packet Fody, das bin ich gerade am Ändern.
Was ich bisher gelesen habe, sollte das TreeView selbst expanden, wenn IsSelected gesetzt wird.
Die Lösungen im Netz sind entweder CodeBehind, Behaiviors, oder Dependency Properties.
Aber das müsste doch in WPF einfacher gehen, oder?
Danke Euch
"Hier könnte Ihre Werbung stehen..."