Search code examples
c#wpfdata-bindinggroupbox

binding groupboxes to may stackpanel


I want to bind Groupboxes to my stackpanel.

c#:

internal ObservableCollection<GroupBox> BindingTest
{
    get
    {
        ObservableCollection<GroupBox> collection = new ObservableCollection<GroupBox>();
        for (int counter = 0; counter < 5; counter++)
        {
            GroupBox groupBox = new GroupBox();
            groupBox.Header = " ... Header ... ";
            groupBox.Content = " ... Content ... ";
            collection.Add(groupBox);
        }

            return collection;
    }
}

and the xaml code:

<StackPanel x:Name="Dynamic" Grid.Row="1" Margin="29,118,6,0">
    <ItemsControl ItemsSource="{Binding Path=BindingTest}" Height="482">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <GroupBox>
                    <GroupBox.Header>{Binding Path=Header}</GroupBox.Header>
                    <GroupBox.Content>{Binding Path=Content}</GroupBox.Content>
                </GroupBox>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</StackPanel>

where does my error in reasoning?


Solution

  • In WPF Binding, you usually don't bind to Controls, you just bind to objects and let the Markup handle UI details. Ideally your objects should implement INotifyPropertyChanged to notify the Binding of property changes. Control creation is handled already by the DataTemplate, it already creates a GroupBox for you and binds its properties to the properties of the object used in the binding.

    Your ViewModel should, if possible, not know anything about the UI, or use any Controls. The MVVM pattern is meant to decouple UI and Data/Logic.

    The class of your data objects could look something like this:

    public class DataObject : INotifyPropertyChanged
    {
        private string header;
        private string content;
    
        public string Header {
            get { return header; }
            set { header = value; RaisePropertyChanged("Header"); }
        }
    
        public string Content {
            get { return content; }
            set { content= value; RaisePropertyChanged("Content"); }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected void RaisePropertyChanged(string propertyName) {
            var handler = PropertyChanged;
            if (handler != null) { 
                handler(this, new PropertyChangedEventArgs(propertyName)); 
            }
        }
    }
    

    The property you bind to would also look different:

    internal ObservableCollection<DataObject> BindingTest
    {
        get
        {
            ObservableCollection<DataObject> collection = new ObservableCollection<DataObject>();
            for (int counter = 0; counter < 5; counter++)
            {
                DataObject item = new DataObject ();
                item.Header = " ... Header ... ";
                item.Content = " ... Content ... ";
                collection.Add(item );
            }
    
                return collection;
        }
    }
    

    I assume creating a new Collection every time the property is accessed is just for testing purposes.