Search code examples
wpfmvvmdatatemplategroupbox

Binding for a GroupBox HeaderTemplate with MVVM


I want to create a GroupBox with a custom header, where besides the header title, i want to have an icon that is associated with a certain MVVM binding.

For example i got it working using this approach:

View:

<GroupBox>
    <GroupBox.Header>
        <StackPanel Orientation="Horizontal">
            <Image Height="18" VerticalAlignment="Center" Source="{Binding BondHead2Enabled, Converter={StaticResource StateToIconConverter}}" />
            <Label Content="Bond Head 2"/>
        </StackPanel>
    </GroupBox.Header>
    <finalBondView:BondheadTemplateView Content="{Binding BondHead2Content}"/>
</GroupBox>

ViewModel

public bool BondHead2Enabled => false;

public BondHeadTemplateViewModel BondHead2Content
{
    get { return _bondheadContents[1]; }
    set
    {
        if (_bondheadContents[1] != value && value != null)
        {
            _bondheadContents[1] = value;
            RaisePropertyChanged("BondHead2Content");
        }
    }
}

However with this approach i have to repeat a lot of code on each groupbox i have. So i want to turn this into a Header Template where i can just associate a style instead of copy pasting the header. Therefore i created this style:

Style

<Style x:Key="StatusGroupBox" TargetType="{x:Type GroupBox}">
    <Setter Property="HeaderTemplate">
        <Setter.Value>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Image Height="18" VerticalAlignment="Center" Source="{Binding EnabledStatus, RelativeSource={RelativeSource AncestorType=GroupBox}, Converter={StaticResource StateToIconConverter}}" />
                    <Label Content="{Binding Header, RelativeSource={RelativeSource AncestorType=GroupBox}}"/>
                </StackPanel>
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

ViewModel

<GroupBox Header="Bond Head 3" Margin="5" Style="{DynamicResource StatusGroupBox}">
    <finalBondView:BondheadTemplateView Content="{Binding BondHead3Content}"/>
</GroupBox>

I can get the content for the label using this style, but i can't get the boolean value that i need to know which icon to display, named EnabledStatus in the style. So how can i pass this information to te style in a generic way?


Solution

  • After reading a bit more on the recommended topics I found a effective way to do this. Instead of binding just a String to the Header property, i binded a structure with both a Title (string) and a status (boolean). Then i read each field in the style. The code:

    Support class

    public class StatusHeaderTemplate
    {
        public string HeaderTitle { get; set; }
        public bool HeaderStatus { get; set; }
    
        public StatusHeaderTemplate(string title, bool status)
        {
            HeaderTitle = title;
            HeaderStatus = status;
        }
    }
    

    Style

    <Style x:Key="MountainTopStatusGroupBox" TargetType="{x:Type GroupBox}">
        <Setter Property="HeaderTemplate">
            <Setter.Value>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Image Source="{Binding HeaderStatus, Converter={StaticResource StateToIconConverter}}" />
                        <Label Content="{Binding HeaderTitle}"/>
                    </StackPanel>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    

    View

    <GroupBox Margin="5" Header="{Binding BondHead1StatusHeader}" Style="{DynamicResource MountainTopStatusGroupBox}">
        <finalBondView:BondheadTemplateView Content="{Binding BondHead1Content}"/>
    </GroupBox>
    

    ViewModel

    public StatusHeaderTemplate BondHead1StatusHeader => new StatusHeaderTemplate("Bond Head 1", true);