WPF Binding TabControl элемент содержимого для различных шаблонов данных - PullRequest
0 голосов
/ 15 мая 2019

Я делаю приложение WPF, используя шаблон MVVM, который имеет 2 модели (Месяц, Год), 1 Viewmodel (YearViewModel) и 1 View (YearView), отображаемые в MainWindow как UserControl.Модель представления имеет наблюдаемую коллекцию объектов типа для добавления данных.

Я хочу добиться управления вкладками, где первая вкладка отображает информацию о модели года и информацию о других вкладках модели месяца.

Я использовал 2 DataTemplate, объявленный в UserControl.Resources YearView, и в элементе управления вкладками я назначаю шаблоны вкладкам.

Модель года

namespace multi_tabs.Models
{
    public class Year
    {
        public float TotalIncome { get; set; }
        public float TotalExpenses { get; set; }
        public float AverageMonthlyIncome { get; set; }
        public float AverageMonthlyExpenses { get; set; }
    }
}

Модель месяца

namespace multi_tabs.Models
{
    public class Month
    {
        public string Name { get; set; }
        public float Income { get; set; }
        public float Expenses { get; set; }
    }
}

YearViewModel

namespace multi_tabs.ViewModels
{
    public sealed class YearViewModel
    {
        public ObservableCollection<object> Tabs { get; set; }

        public YearViewModel ()
        {
            Tabs = new ObservableCollection<object>();
            LoadMonths();
            CalculateAnnualSummary();
        }

        private void LoadMonths ()
        {
            Tabs.Add(new Month { Name = "January", Income = 100.5f, Expenses = 87.4f });
            Tabs.Add(new Month { Name = "February", Income = 100.5f, Expenses = 87.4f });
            Tabs.Add(new Month { Name = "March", Income = 100.5f, Expenses = 87.4f });
            Tabs.Add(new Month { Name = "April", Income = 145600.5f, Expenses = 87.4f });
            Tabs.Add(new Month { Name = "May", Income = 100.5f, Expenses = 8457.4f });
            Tabs.Add(new Month { Name = "June", Income = 100.5f, Expenses = 87.4f });
            Tabs.Add(new Month { Name = "July", Income = 104560.5f, Expenses = 87.4f });
            Tabs.Add(new Month { Name = "August", Income = 100.5f, Expenses = 87.4f });
            Tabs.Add(new Month { Name = "September", Income = 100.5f, Expenses = 87.4f });
            Tabs.Add(new Month { Name = "October", Income = 100.5f, Expenses = 87.4f });
            Tabs.Add(new Month { Name = "November", Income = 1786700.5f, Expenses = 84567.4f });
            Tabs.Add(new Month { Name = "December", Income = 100.5f, Expenses = 87.4f });
        }

        private void CalculateAnnualSummary ()
        {
            float _totalIncome = 0;
            float _totalExpenses = 0;
            float _averageIncome = 0;
            float _averageExpenses = 0;

            foreach (var month in Tabs)
            {
                _totalIncome += ((Month)month).Income;
                _totalExpenses += ((Month)month).Expenses;
            }

            _averageIncome = _totalIncome / Tabs.Count;
            _averageExpenses = _totalExpenses / Tabs.Count;

            Tabs.Insert(0, new Year { TotalIncome = _totalIncome,
                                      TotalExpenses = _totalExpenses,
                                      AverageMonthlyIncome = _averageIncome,
                                      AverageMonthlyExpenses = _averageExpenses });
        }
    }
}

YearView

<UserControl x:Class="multi_tabs.Views.YearView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:multi_tabs.Views"
             xmlns:viewmodels="clr-namespace:multi_tabs.ViewModels"
             xmlns:view="clr-namespace:multi_tabs.Views"
             xmlns:model="clr-namespace:multi_tabs.Models"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Resources>

        <DataTemplate x:Key="YearTemplate" DataType="{x:Type viewmodels:YearViewModel}">
            <StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Income:"/>
                    <TextBlock Text="{Binding Income}" Margin="5,0,0,0"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Expenses:"/>
                    <TextBlock Text="{Binding Expenses}" Margin="5,0,0,0"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Average Monthly Income:"/>
                    <TextBlock Text="{Binding AverageMonthlyIncome}" Margin="5,0,0,0"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Average Monthly Expenses:"/>
                    <TextBlock Text="{Binding AverageMonthlyExpenses}" Margin="5,0,0,0"/>
                </StackPanel>
            </StackPanel>
        </DataTemplate>

        <DataTemplate x:Key="MonthTemplate" DataType="{x:Type viewmodels:YearViewModel}">
            <StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Income:"/>
                    <TextBlock Text="{Binding Income}" Margin="5,0,0,0"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Expenses:"/>
                    <TextBlock Text="{Binding Expenses}" Margin="5,0,0,0"/>
                </StackPanel>
            </StackPanel>
        </DataTemplate>

    </UserControl.Resources>
    <Grid>
        <TabControl ContentTemplate="{StaticResource MonthTemplate}" ItemsSource="{Binding Tabs}">
            <TabItem Header="Annual Summary" ContentTemplate="{StaticResource YearTemplate}"/>
            <TabItem Header="January"/>
            <TabItem Header="February"/>
            <TabItem Header="March"/>
            <TabItem Header="April"/>
            <TabItem Header="May"/>
            <TabItem Header="June"/>
            <TabItem Header="July"/>
            <TabItem Header="August"/>
            <TabItem Header="September"/>
            <TabItem Header="October"/>
            <TabItem Header="November"/>
            <TabItem Header="December"/>
        </TabControl>
    </Grid>
</UserControl>

Шаблоны данных найдены и отображаются правильно, но в привязке не отображаются данные, содержащиеся в вкладках ObservableCollection.

Что я делаю не так?

Спасибо

РЕДАКТИРОВАТЬ:

Я использую Visual Studio Community 2017, и окно вывода выглядит чистым на мой взгляд, но на всякий случай я вставляю показанные строки:

'multi_tabs.exe' (CLR v4.0.30319: DefaultDomain): 'C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll' cargado. No se encuentra el archivo PDB o no se puede abrir.
'multi_tabs.exe' (CLR v4.0.30319: DefaultDomain): 'C:\Users\n60pc\OneDrive\Escritorio\JAF\multi_tabs\bin\Debug\multi_tabs.exe' cargado. Símbolos cargados.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.dll' cargado. No se encuentra el archivo PDB o no se puede abrir.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\WindowsBase\v4.0_4.0.0.0__31bf3856ad364e35\WindowsBase.dll' cargado. No se encuentra el archivo PDB o no se puede abrir.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll' cargado. No se encuentra el archivo PDB o no se puede abrir.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll' cargado. No se encuentra el archivo PDB o no se puede abrir.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Windows\Microsoft.Net\assembly\GAC_32\PresentationCore\v4.0_4.0.0.0__31bf3856ad364e35\PresentationCore.dll' cargado. No se encuentra el archivo PDB o no se puede abrir.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xaml\v4.0_4.0.0.0__b77a5c561934e089\System.Xaml.dll' cargado. No se encuentra el archivo PDB o no se puede abrir.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\PrivateAssemblies\Runtime\Microsoft.VisualStudio.Debugger.Runtime.dll' cargado. 
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll' cargado. No se encuentra el archivo PDB o no se puede abrir.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll' cargado. No se encuentra el archivo PDB o no se puede abrir.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\mscorlib.resources\v4.0_4.0.0.0_es_b77a5c561934e089\mscorlib.resources.dll' cargado. El módulo se compiló sin símbolos.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework.Aero2\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.Aero2.dll' cargado. No se encuentra el archivo PDB o no se puede abrir.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework.resources\v4.0_4.0.0.0_es_31bf3856ad364e35\PresentationFramework.resources.dll' cargado. El módulo se compiló sin símbolos.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework-SystemXml\v4.0_4.0.0.0__b77a5c561934e089\PresentationFramework-SystemXml.dll' cargado. No se encuentra el archivo PDB o no se puede abrir.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\UIAutomationTypes\v4.0_4.0.0.0__31bf3856ad364e35\UIAutomationTypes.dll' cargado. No se encuentra el archivo PDB o no se puede abrir.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationCore.resources\v4.0_4.0.0.0_es_31bf3856ad364e35\PresentationCore.resources.dll' cargado. El módulo se compiló sin símbolos.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Users\n60pc\AppData\Local\Temp\VisualStudio.XamlDiagnostics.8336\Microsoft.VisualStudio.DesignTools.WpfTap.dll' cargado. No se encuentra el archivo PDB o no se puede abrir.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.Serialization\v4.0_4.0.0.0__b77a5c561934e089\System.Runtime.Serialization.dll' cargado. No se encuentra el archivo PDB o no se puede abrir.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\SMDiagnostics\v4.0_4.0.0.0__b77a5c561934e089\SMDiagnostics.dll' cargado. No se encuentra el archivo PDB o no se puede abrir.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ServiceModel.Internals\v4.0_4.0.0.0__31bf3856ad364e35\System.ServiceModel.Internals.dll' cargado. No se encuentra el archivo PDB o no se puede abrir.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.Serialization.resources\v4.0_4.0.0.0_es_b77a5c561934e089\System.Runtime.Serialization.resources.dll' cargado. El módulo se compiló sin símbolos.
'multi_tabs.exe' (CLR v4.0.30319: multi_tabs.exe): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\UIAutomationProvider\v4.0_4.0.0.0__31bf3856ad364e35\UIAutomationProvider.dll' cargado. No se encuentra el archivo PDB o no se puede abrir.

РЕДАКТИРОВАТЬ 2:

MainWindow

<Window x:Class="multi_tabs.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:multi_tabs"
        xmlns:views="clr-namespace:multi_tabs.Views"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <views:YearView/>
    </Grid>
</Window>

Ответы [ 2 ]

2 голосов
/ 15 мая 2019

Избавьтесь от TabItems от разметки XAML и используйте неявные DataTemplates для Month и Year:

<TabControl ItemsSource="{Binding Tabs}">
    <TabControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Name, FallbackValue='Annual Summary'}" />
        </DataTemplate>
    </TabControl.ItemTemplate>
    <TabControl.Resources>
        <DataTemplate DataType="{x:Type local:Year}">
            <StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Income:"/>
                    <TextBlock Text="{Binding TotalIncome}" Margin="5,0,0,0"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Expenses:"/>
                    <TextBlock Text="{Binding TotalExpenses}" Margin="5,0,0,0"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Average Monthly Income:"/>
                    <TextBlock Text="{Binding AverageMonthlyIncome}" Margin="5,0,0,0"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Average Monthly Expenses:"/>
                    <TextBlock Text="{Binding AverageMonthlyExpenses}" Margin="5,0,0,0"/>
                </StackPanel>
            </StackPanel>
        </DataTemplate>

        <DataTemplate DataType="{x:Type local:Month}">
            <StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Income:"/>
                    <TextBlock Text="{Binding Income}" Margin="5,0,0,0"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Expenses:"/>
                    <TextBlock Text="{Binding Expenses}" Margin="5,0,0,0"/>
                </StackPanel>
            </StackPanel>
        </DataTemplate>
    </TabControl.Resources>
</TabControl>
1 голос
/ 15 мая 2019

В дополнение к отличному ответу mm8, я предлагаю следующее в MainWindow (это полная замена того, что есть в MainWindow, но, очевидно, вы можете при желании добавить все другие вещи вокруг этого UserControl):

<Window.Resources>
    <DataTemplate DataType="{x:Type viewmodels:YearViewModel}">
        <!-- 
          The YearViewModel will be the DataContext here, and the YearView
          inherits that from here. This is similar to the viewmodels:Year and Month
          templates now found in mm8's answer. 
        -->
        <local:YearView />
    </DataTemplate>
</Window.Resources>
<Grid>
    <ContentControl>
        <ContentControl.Content>
            <!-- 
            This creates a YearViewModel. The framework uses the implicit datatemplate above
            to figure out how the ContntControl will display this Content. 
            -->
            <viewmodels:YearViewModel />
        </ContentControl.Content>
    </ContentControl>
</Grid>

Обратите внимание, что это не единственный способ в мире установить DataContext экземпляра UserControl.Это тоже работает.В этом примере неявная таблица данных в Window.Resources больше не определяется.

    <ContentControl>
        <ContentControl.Content>
            <viewmodels:YearViewModel />
        </ContentControl.Content>
        <ContentControl.ContentTemplate>
            <DataTemplate>
                <local:YearView />
            </DataTemplate>
        </ContentControl.ContentTemplate>
    </ContentControl>

И это тоже.Установка DataContext в явном виде считается неразумной, поскольку она нарушает любые другие привязки в YearView.Но как есть, это работает.

    <local:YearView>
        <local:YearView.DataContext>
            <viewmodels:YearViewModel />
        </local:YearView.DataContext>
    </local:YearView>
...