B.Balamanigandan B.Balamanigandan - 1 year ago 229
C# Question

Create a Custom Control with the combination of multiple controls in WPF C#

I wish to create a Custom Control, it should be a combination of predefined controls like Textbox, Button, ListBox, etc.,

Kindly refer the following Controls (Just a Sample)

<RowDefinition Height="30" />
<RowDefinition Height="50" />
<ColumnDefinition Width="300" />
<ColumnDefinition Width="100" />
<TextBox Grid.Column="0" />
<Button Grid.Column="1" Content="Add" Margin="20,0" />
<ListBox ItemsSource="{Binding textBox}" Grid.Row="1" Margin="0,25">
<ListBoxItem />

I need a combination of controls in a single custom control. I need to add the Textbox values in a ListItem while I'm hitting the button and finally I need the List from this control.

Expected Custom Control (Just a Sample)

<cust:MultiControl ItemsSource="{Binding stringCollection}" />

I need to get the list of string from the user. I added a TextBox to get the input from the User. I added a Button to add the text in a
. To display the List I added a ListBox.

I need a Single control, it should inherit these three controls. In that I need an
for two way binding. If the
is updated, it should update the ItemSource.

I'm using this structure in more than 15 places. So, I wish to make it as Custom control. Kindly assist me how to implement this as a single control ?

enter image description here

I don't need a User Control, I need a Custom Control kindly assist me...

Item Source ViewModel Collection is not updating even-though the ItemsSource has value.

enter image description here

Answer Source

I've made you a minimal example of that desired CustomControl.

The Control

public class MyCustomControl : ItemsControl {

        static MyCustomControl() {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl), new FrameworkPropertyMetadata(typeof(MyCustomControl)));

        private Button _addButton;
        private TextBox _textBox;
        private ListView _itemsView;

        public override void OnApplyTemplate() {
            this._addButton = this.GetTemplateChild("PART_AddButton") as Button;
            this._textBox = this.GetTemplateChild("PART_TextBox") as TextBox;
            this._itemsView = this.GetTemplateChild("PART_ListBox") as ListView;

            this._addButton.Click += (sender, args) => {
                (this.ItemsSource as IList<string>).Add(this._textBox.Text);
            this._itemsView.ItemsSource = this.ItemsSource;

        public ICommand DeleteCommand => new RelayCommand(x => { (this.ItemsSource as IList<string>).Remove((string)x); });

The Template

 <Style TargetType="{x:Type local:MyCustomControl}">
    <Setter Property="Template">
            <ControlTemplate TargetType="{x:Type local:MyCustomControl}">
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                                <ColumnDefinition Width="300" />
                                <ColumnDefinition Width="100" />
                            <TextBox x:Name="PART_TextBox" Grid.Column="0" />
                            <Button x:Name="PART_AddButton" Grid.Column="1" Content="Add" Margin="20,0" />
                        <ListView ItemsSource="{TemplateBinding ItemsSource}" Grid.Row="1" Margin="0,25" x:Name="PART_ListBox" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
                                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
                                        <TextBlock Text="{Binding}"/>
                                        <Button Content="X" Foreground="Red" 
                                                Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MyCustomControl}}, Path=DeleteCommand}" 
                                                CommandParameter="{Binding}" Margin="10,0,0,0"></Button>


public class RelayCommand : ICommand
        #region Fields

        private readonly Action<object> _execute;
        private readonly Predicate<object> _canExecute;

        #endregion // Fields

        #region Constructors

        public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
            if (execute == null)
                throw new ArgumentNullException(nameof(execute));

            this._execute = execute;
            this._canExecute = canExecute;

        #endregion // Constructors

        #region ICommand Members

        public bool CanExecute(object parameter)
            return this._canExecute == null || this._canExecute(parameter);

        public event EventHandler CanExecuteChanged {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }

        public void Execute(object parameter)

        #endregion // ICommand Members


 <local:MyCustomControl ItemsSource="{Binding Collection}"/>

Note Do not use a List as your ItemsSource. Rather use an ObservableCollection since it notifies the View automaticly and you dont have to deal with that Update-Stuff