Laden...

An zusätzliches Item in ObservableCollection binden

Erstellt von ByteDevil vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.253 Views
ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren
An zusätzliches Item in ObservableCollection binden

Hi,

ich schreibe gerade an einem kleinen Tool zur Zeiterfassung. Nichts großartig kompliziertes und nichts was die Welt revolutioniert. Mache das hauptsächlich um mir das MVVM Pattern beizubringen. Bisher funktioniert auch alles prima.

Ein kurzer Überblick über meine Struktur der ViewModels:

  • DayRecordViewModel
  • MonthRecordViewModel
  • YearRecordViewModel

Ein DayRecordViewModel beinhaltet alles über den Arbeitstag: Datum, Anfang, Ende, Pause, Soll...
Ein MonthRecordViewModel hat eine ObservableCollection<DayRecordViewModel>
Ein YearRecordViewModel hat eine ObservableCollection<MonthRecordViewModel>

Jedes MonthRecordViewModel bedient ein DataGrid und das YearRecordViewModel ein TabControl. Das YearRecordViewModel ist an die ItemSource des TabControls gebunden und somit habe ich einen Tab für jeden Monat.

Nun zu meinem Problem: Ich hätte gern einen dreizehnten Tab am Ende der "Übersicht" heißt und welcher vielleicht auch eine andere Farbe hat (färbe die Tabs mittels TabControl.AlternationIndex in dessen Style ein).
Ich habe aber keine Ahnung wie ich das machen soll. Hier mal der XAML Code von meinem TabControl:

<TabControl x:Name="tabControl" TabStripPlacement="Bottom" ItemsSource="{Binding MonthRecordViewModels}" AlternationCount="2"
            IsSynchronizedWithCurrentItem="True" SelectedItem="{Binding SelectedMonthRecordViewModel, Mode=TwoWay}">
    <TabControl.ItemContainerStyle>
        <Style TargetType="{x:Type TabItem}">
            <Setter Property="Header" Value="{Binding Path=Month, Converter={StaticResource shortMonthConverter}}"/>
            <Style.Triggers>
                <Trigger Property="TabControl.AlternationIndex" Value="0">
                    <Setter Property="Background" Value="LightSeaGreen"/>
                </Trigger>
                <Trigger Property="TabControl.AlternationIndex" Value="1">
                    <Setter Property="Background" Value="LightGreen"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </TabControl.ItemContainerStyle>
    <TabControl.ContentTemplate>
        <DataTemplate>
            <local:MonthPlan/>
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>
5.657 Beiträge seit 2006
vor 4 Jahren

Du kannst dafür eine CompositeCollection verwenden: How to: Implement a CompositeCollection

Weeks of programming can save you hours of planning

ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren

Du kannst dafür eine CompositeCollection verwenden:
>

Ahhh vielen Dank 😃

So ganz klappt es aber bei mir noch nicht. Hier mal der gesamte XAML Code von dem Control:


<UserControl x:Class="WorkTimeTracker.View.Controls.YearPlan"
             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:converters="clr-namespace:WorkTimeTracker.View.Converters"
             xmlns:valRules="clr-namespace:WorkTimeTracker.View.ValidationRules"
             xmlns:viewModels="clr-namespace:WorkTimeTracker.ViewModels"
             xmlns:local="clr-namespace:WorkTimeTracker.View.Controls"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800" x:Name="this">
    <UserControl.Resources>
        <converters:IntToShortMonthLocalizedConverter x:Key="shortMonthConverter"/>
        <DataTemplate DataType="{x:Type viewModels:MonthRecordViewModel}">
            <local:MonthPlan/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type viewModels:YearSumaryViewModel}">
            <local:YearSummary/>
        </DataTemplate>
    </UserControl.Resources>
    <TabControl x:Name="tabControl" TabStripPlacement="Bottom" AlternationCount="2"
                IsSynchronizedWithCurrentItem="True" SelectedItem="{Binding SelectedMonthRecordViewModel, Mode=TwoWay}">
        <TabControl.ItemsSource>
            <CompositeCollection>
                <CollectionContainer x:Name="monthCollectionContainer" Collection="{Binding MonthRecordViewModels}"/>
                <TabItem Header="Übersicht">
                    <local:YearSummary DataContext="{Binding ElementName=this, Path=DataContext}"/>
                </TabItem>
            </CompositeCollection>
        </TabControl.ItemsSource>
        <TabControl.ItemContainerStyle>
            <Style TargetType="{x:Type TabItem}">
                <Setter Property="Header" Value="{Binding Source=monthCollectionContainer, Path=Month, Converter={StaticResource shortMonthConverter}}"/>
                <Style.Triggers>
                    <Trigger Property="TabControl.AlternationIndex" Value="0">
                        <Setter Property="Background" Value="LightSeaGreen"/>
                    </Trigger>
                    <Trigger Property="TabControl.AlternationIndex" Value="1">
                        <Setter Property="Background" Value="LightGreen"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </TabControl.ItemContainerStyle>
    </TabControl>
</UserControl>

Nun ist der Extra-Tab zwar da, die Monate aber nicht mehr.
In der Ausgabe sind folgende Fehlermeldungen zu sehen:

Fehlermeldung:
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=MonthRecordViewModels; DataItem=null; target element is 'CollectionContainer' (HashCode=31674992); target property is 'Collection' (type 'IEnumerable')

Fehlermeldung:
System.Windows.Data Error: 40 : BindingExpression path error: 'Month' property not found on 'object' ''String' (HashCode=1434043879)'. BindingExpression:Path=Month; DataItem='String' (HashCode=1434043879); target element is 'TabItem' (Name=''); target property is 'Header' (type 'Object')

MonthRecordViewModel.Month ist übrigens nur ein Int zwischen 1-12 und shortMonthConverter macht aus einem int einfach Jan, Feb, Mrz usw. Ohne den Converter würde halt der Header der Tabs einfach aus der Zahl bestehen.

ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren

Habe es doch noch geschafft. Hier die Lösung:


<TabControl x:Name="tabControl" TabStripPlacement="Bottom" AlternationCount="2"
                IsSynchronizedWithCurrentItem="True" SelectedItem="{Binding SelectedMonthRecordViewModel, Mode=TwoWay}">
        <TabControl.Resources>
            <CollectionViewSource Source="{Binding Path=MonthRecordViewModels}" x:Key="ItemsCollectionViewSource"/>
        </TabControl.Resources>
        <TabControl.ItemsSource>
            <CompositeCollection>
                <CollectionContainer x:Name="monthCollectionContainer" Collection="{Binding Source={StaticResource ItemsCollectionViewSource}}"/>
                <TabItem Header="Übersicht">
                    <local:YearSummary DataContext="{Binding YearSumaryViewModel}"/>
                </TabItem>
            </CompositeCollection>
        </TabControl.ItemsSource>
        <TabControl.ItemContainerStyle>
            <Style TargetType="{x:Type TabItem}">
                <Setter Property="Header" Value="{Binding Month, Converter={StaticResource shortMonthConverter}}"/>
                <Style.Triggers>
                    <Trigger Property="TabControl.AlternationIndex" Value="0">
                        <Setter Property="Background" Value="LightSeaGreen"/>
                    </Trigger>
                    <Trigger Property="TabControl.AlternationIndex" Value="1">
                        <Setter Property="Background" Value="LightGreen"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </TabControl.ItemContainerStyle>
    </TabControl>