1

I created a treeview following a youtube video and then made a datagrid that show some files from a chosen tar.gz file. Both of them use DataContext to show themselves on the program. The problem is that the TreeView disappear when the DataGrid is showing. I guess the problem is that both can't use DataContext like I'm using but I don't know a solution for it.

XAML Code

<Window x:Class="RFAnalyzerMain.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:RFAnalyzerMain"
        mc:Ignorable="d"
        Title="MainWindow"
        Height="600" Width="900"
        MinHeight="400" MinWidth="750"
        Closing="Window_Closing" Loaded="Window_Loaded">
    <Border Padding="2">
        <Grid>
            <!-- #region Grid Definitions -->

            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="200" />
                <ColumnDefinition Width="10*" />
                <ColumnDefinition Width="15" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="20" />
                <RowDefinition Height="20" />
                <RowDefinition Height="25*" />
                <RowDefinition Height="20" />
            </Grid.RowDefinitions>

            <!--#endregion-->

            <DockPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">
                <Menu DockPanel.Dock="Top">
                    <MenuItem Header="_File">
                        <MenuItem Header="Choose File to Read" x:Name="ChosenFile" Click="ChosenFile_Click" />
                    </MenuItem>
                </Menu>
            </DockPanel>

            <Border Grid.Row="2" Padding="5 0" BorderThickness="0" BorderBrush="Gray">
                <Grid>

                    <!-- Grid Definitions -->
                    <Grid.RowDefinitions>
                        <RowDefinition Height="25" />
                        <RowDefinition Height="*" />
                        <RowDefinition Height="20" />
                    </Grid.RowDefinitions>

                    <TextBlock Text="Folder" FontWeight="Bold" FontSize="18" Grid.Row="0"
                       VerticalAlignment="Center" HorizontalAlignment="Left" />

                    <!-- A TreeView of Fodlers -->
                    <Grid Grid.Row="1" Margin="0 0 0 5">
                        <TreeView x:Name="FolderView" ItemsSource="{Binding Items}" FontSize="10">
                            
                            <TreeView.ItemContainerStyle>
                                <Style TargetType="{x:Type TreeViewItem}">
                                    <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
                                </Style>
                            </TreeView.ItemContainerStyle>

                            <TreeView.ItemTemplate>
                                <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                                    <StackPanel Orientation="Horizontal">
                                        <Image Width="15" Margin="3"
                                                   Source="{Binding Type,
                                                       Converter={x:Static local:HeaderToImageConverter.Instance}}" />
                                        <TextBlock VerticalAlignment="Center" Text="{Binding Name}" />
                                    </StackPanel>
                                </HierarchicalDataTemplate>
                            </TreeView.ItemTemplate>
                            
                        </TreeView>
                    </Grid>


                    <Button Content="Read" Grid.Row="2" Margin="0 0 0 0" Width="60" />
                </Grid>
            </Border>

            <DataGrid Grid.Row="2" Grid.Column="1" ItemsSource="{Binding FileProperties}" />

            <Button Grid.Column="2" Grid.Row="2">
                <Image Source="Images/Button Left Arrow.png" Width="10" />
            </Button>

        </Grid>
    </Border>
</Window>

Behind-Code

using System.IO;
using System.Windows;

namespace RFAnalyzerMain
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        #region Constructor

        /// <summary>
        /// Default Constructor
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();
            // Treeview
            DataContext = new DirectoryStructureViewModel();
        }

        #endregion

        #region User Events

        /// <summary>
        /// Choose a file from the explorer
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ChosenFile_Click(object sender, RoutedEventArgs e)
        {
            ExplorerHandler.OpenExplorer();
            // Writes out all the files inside the file opened in the explorer
            DataContext = new FilePropertiesViewModel();
        }

        #endregion

        #region Starting Program

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            if (FilePaths.GZipDirectory.Exists == true)
                Remove.FilesAndFolders();
        }

        #endregion

        #region Closing Program

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            Remove.FilesAndFolders();
        }

        #endregion


    }
}

If you need to see more code just ask and I'll edit the post and add the code asked for.

Fisheer
  • 67
  • 6
  • Make another view model (set it as `DataContext` of window once!) and add those too viewmodels as getter-only properties. Then you can bind `ItemsSource`s to `FirtVMProperty.Items` and `AnotherVMProperty.FileProperties`. – Sinatr Aug 03 '20 at 07:34
  • @Sinatr Okay, thanks! will this work like I want the DataGrid to be empty and only show when a file has been chosen? – Fisheer Aug 03 '20 at 07:47
  • You can simply control visibility of `DataGrid` (and show text "select file first" instead) or the property can have logic in getter to return *empty* view model if file is not selected. – Sinatr Aug 03 '20 at 08:32
  • Or make the collection in a property of the treeview item viewmodel and bind to that property on the selected treeview node. You need a behaviour to do this but one would be easily googled. When nothing is selected then the datagrid has nothing so it'd be empty. – Andy Aug 03 '20 at 08:35
  • @Sinatr Is there a way you could show how to add the two viewmodels to this new class I made that's going to be the DataContext? :) – Fisheer Aug 03 '20 at 08:43

2 Answers2

1

Since you implemented your logic in the code-behind, why don't you simply set the DataContext of the DataGrid in the event handler?:

private void ChosenFile_Click(object sender, RoutedEventArgs e)
{
    ExplorerHandler.OpenExplorer();
    // Writes out all the files inside the file opened in the explorer
    dataGrid.DataContext = new FilePropertiesViewModel();
}

XAML:

<DataGrid x:Name="dataGrid" Grid.Row="2" Grid.Column="1" ItemsSource="{Binding FileProperties}" />

Then the TreeView won't disappear when you click on the button.

The other option would be to use a shared view model as suggested by @Sinatr but this will require some refactoring from what you currently have.

mm8
  • 163,881
  • 10
  • 57
  • 88
0

Typically you have to set DataContext once:

public MainWindow()
{
    InitializeComponent();
    DataContext = new MainWindowViewModel();
}

View model can have multiple properties:

public class MainWindowViewModel: INotifyPropertyChanaged
{
    public DirectoryStructureViewModel Files { get; } = new DirectoryStructureViewModel();

    FilePropertiesViewModel _selectedFile;
    public FilePropertiesViewModel SelectedFile
    {
        get => _selectedFile;
        set
        {
            _selectedFile = value;
            OnPropertyChanged();
            OnPropertyChanged(nameof(IsSelectedFileVisible));
        }
    }
    public bool IsSelectedFileVisible => SelectedFile != null;
}

To which you can bind in the view:

<TreeView ItemsSource="{Binding Files.Items}"
          SelectedItemChanged="TreeView_OnSelectedItemChanged" ... />
<DataGrid ItemsSource="{Binding SelectedFile.FileProperties}"
          Visibility="{Binding IsSelectedFileVisible, Converter={StaticResource BoolToVis}}" ... />

And

void TreeView_OnSelectedItemChanged(...)
{
    var vm = (MainWindowViewModel)DataContext;
    vm.SelectedFile = ...
}

References: 1, 2, 3.

Sinatr
  • 20,892
  • 15
  • 90
  • 319