MVVM Tabbed Interface Panels Appear to Share a Single, Common Resource

143 views Asked by At

I am creating a WPF Tabbed Interface utility program using MVVM Light. While free-standing dialog boxes live in their own .xaml files, my understanding was that to create tabbed interface panels, the code for those should reside in a DataTemplate within my MainWindow.xaml.

Everything was working fine until I needed to customize the appearance of the DataGrid. What I wanted was to call an event handler when a grid was created that would iterate through the columns and do some custom things for certain columns. So I added an Initialized event handler to the DataGrid. It only gets called when the first tab with a DataGrid is created... or when I close all the tabs and open a new first DataGrid tab. A little more investigation and I discover that DataContextChanged happens whenever I create a subsequent grid or click between tabs.

I'm thinking that I've committed a design flaw, that while there is a separate view-model for each grid, there is only a single, common grid resource, but am unsure how to correct it.

My Question: How do I go about creating a completely separate grid for each tab?

Sample View with several tabs open

DataTemplate from MainWindow.xaml:

<Window...>
    <Window.Resources>
    <DataTemplate DataType="{x:Type vm:GridViewModel}">
        <Grid>
            <DataGrid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,32" RowHeight="{Binding RowHeight}" SelectionUnit="Cell" 
                      IsReadOnly="True" LoadingRow="DataGrid_LoadingRow" ItemsSource="{Binding RecordSet}" AutoGenerateColumns="false" 
                      Initialized="DataGrid_Initialized" DataContextChanged="DataGrid_DataContextChanged" >

            </DataGrid>
        </Grid>
    </DataTemplate>
    </Window.Resources>
</Window>

TabControl from within Grid from MainWindow.xml

<TabControl x:Name="DocumentArea" ItemsSource="{Binding Workspaces}" SelectedIndex="{Binding SelectedIndex}" HorizontalAlignment="Stretch" Margin="0,35,0,35" VerticalAlignment="Stretch">
    <TabControl.ItemTemplate>
        <DataTemplate>
            <WrapPanel>
                <TextBlock Text="{Binding Header}" />
                <Button Command="{Binding CloseCommand}" Content="X" Margin="4,0,0,0" FontFamily="Courier New" Width="17" Height="17" VerticalContentAlignment="Center" />
            </WrapPanel>
        </DataTemplate>
    </TabControl.ItemTemplate>
</TabControl>

Example of a method in MainViewModel.cs that creates a Grid:

private void ShowAccountsGrid()
{
    GridViewModel viewModel = new GridViewModel { Header = "QuickBooks Chart of Accounts" };

    Workspaces.Add(viewModel);
    SelectedIndex = Workspaces.IndexOf(viewModel);
    viewModel.RecordSet = _quickBooksHelper.AccountList;
}

Relevant code from GridViewModel.cs:

public class GridViewModel : WorkspaceViewModel
{
    private readonly IDataService _dataService;

    public RelayCommand DoDeleteRow { get; set; }
    public RelayCommand DoShowRowDetail { get; set; }

    [PreferredConstructor]
    public GridViewModel(IDataService dataService) :base()
    {
        InitBoundFields();

        SetupRelayCommands();
        _dataService = dataService;
        _dataService.GetData(
            (item, error) =>
            {
                if (error != null)
                {
                    // Report error here
                    return;
                }
            });
    }
0

There are 0 answers