Hi,
you can add Button, bind to ICommand property and add new student object.
XAML window:
<Window x:Class="WpfApp1.Window131"
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:WpfApp131"
mc:Ignorable="d"
Title="Mesh Ka_231228" Height="250" Width="400">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<Window.Resources>
<Style TargetType="{x:Type local:FloatingLabelComboBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:FloatingLabelComboBox}">
<StackPanel FlowDirection="LeftToRight">
<Label Content="{TemplateBinding LabelText}"
Foreground="{TemplateBinding LabelForeground}"
FontSize="{TemplateBinding LabelFontSize}"
VerticalAlignment="Stretch"
Margin="-5 0 0 0" />
<ComboBox ItemsSource="{TemplateBinding ItemsSource}"
DisplayMemberPath="{TemplateBinding DisplayMemberPath}"
SelectedItem="{Binding Path=SelectedItem, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
SelectedValue="{Binding Path=SelectedValue, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Foreground="{TemplateBinding Foreground}">
</ComboBox>
<Button Content="Add New" Margin="10"
Command="{Binding Command, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
Visibility="{Binding CommandVisible, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<local:BoolToColorConverter x:Key="BoolToColorConverter"/>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<local:FloatingLabelComboBox Grid.Column="0"
LabelText="Student"
ItemsSource="{Binding StudentsView}"
SelectedItem="{Binding Student}"
DisplayMemberPath="StudentName"
CBConverter="{StaticResource BoolToColorConverter}"
LabelForeground="Black"
Margin="10"
Command="{Binding CmdNew}"/>
<local:FloatingLabelComboBox Grid.Column="1"
LabelText="Blood Group"
ItemsSource="{Binding BloodGroups}"
SelectedValue="{Binding Student.BloodGroup}"
LabelForeground="Black"
Margin="10"/>
<Grid Grid.Row="1" Grid.Column="0" Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Label Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right"
Content="Student:"/>
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Student.StudentName}" Margin="4"/>
<Label Grid.Row="2" Grid.Column="0" HorizontalAlignment="Right"
Content="Bloodgroup:"/>
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Student.BloodGroup}" Margin="4"/>
</Grid>
</Grid>
</Window>
And code:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Linq;
namespace WpfApp131
{
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] String propertyName = "")
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
// contructor: load StudentList
public ViewModel()
{
for (int i = 1; i <= 10; i++)
_studentList.Add(new Student() { StudentId = i, StudentName = $"Student {i}" });
_cvsStudentList.Source = _studentList;
}
internal ObservableCollection<Student> _studentList { get; set; } = new ObservableCollection<Student>();
private CollectionViewSource _cvsStudentList = new CollectionViewSource();
public ICollectionView StudentsView { get => _cvsStudentList.View; }
public ObservableCollection<string> BloodGroups { get; set; } = new ObservableCollection<string>() { "A", "B", "AB", "0" };
private Student _student;
public Student Student
{
get => _student;
set
{
_student = value;
OnPropertyChanged();
StudentsView.Refresh();
}
}
public ICommand CmdNew
{ get => new RelayCommand(CmdNewStudent); }
private void CmdNewStudent(object obj)
{
int lastID = (from s in _studentList orderby s.StudentId descending select s.StudentId).FirstOrDefault();
_studentList.Add(new Student() { StudentId = lastID + 1, StudentName = $"Student {lastID + 1}" });
StudentsView.Refresh();
}
}
public class Student : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] String propertyName = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
public int StudentId { get; set; }
private string _studentName;
public string StudentName
{
get => _studentName;
set
{
_studentName = value;
OnPropertyChanged();
}
}
private string _bloodgroup;
public string BloodGroup
{
get => _bloodgroup;
set
{
_bloodgroup = value;
OnPropertyChanged();
}
}
}
public class FloatingLabelComboBox : Control, INotifyPropertyChanged
{
static FloatingLabelComboBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(FloatingLabelComboBox), new FrameworkPropertyMetadata(typeof(FloatingLabelComboBox)));
}
public FloatingLabelComboBox() => this.Loaded += FloatingLabelComboBox_Loaded;
private void FloatingLabelComboBox_Loaded(object sender, RoutedEventArgs e)
{
Style st = new Style(typeof(ComboBoxItem));
Binding b = new Binding() { Converter = CBConverter };
st.Setters.Add(new Setter(ComboBoxItem.BackgroundProperty, b));
if (CBConverter != null) this.Resources.Add(typeof(ComboBoxItem), st);
}
public static readonly DependencyProperty LabelTextProperty =
DependencyProperty.Register("LabelText", typeof(string),
typeof(FloatingLabelComboBox), new PropertyMetadata(string.Empty));
public string LabelText
{
get { return GetValue(LabelTextProperty).ToString(); }
set { SetValue(LabelTextProperty, value); }
}
public static readonly DependencyProperty LabelForegroundProperty =
DependencyProperty.Register("LabelForeground", typeof(Brush),
typeof(FloatingLabelComboBox), new PropertyMetadata(Brushes.AliceBlue));
public Brush LabelForeground
{
get { return (Brush)GetValue(LabelForegroundProperty); }
set { SetValue(LabelForegroundProperty, value); }
}
public static readonly DependencyProperty LabelFontSizeProperty =
DependencyProperty.Register("LabelFontSize", typeof(double),
typeof(FloatingLabelComboBox), new PropertyMetadata(10.0));
public double LabelFontSize
{
get { return (double)GetValue(LabelFontSizeProperty); }
set { SetValue(LabelFontSizeProperty, value); }
}
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(object),
typeof(FloatingLabelComboBox), new PropertyMetadata(null));
public object ItemsSource
{
get { return GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static readonly DependencyProperty SelectedItemProperty =
DependencyProperty.Register("SelectedItem", typeof(object),
typeof(FloatingLabelComboBox),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
OnSelectedItemChanged));
public object SelectedItem
{
get { return GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FloatingLabelComboBox cc = d as FloatingLabelComboBox;
cc.SelectedItem = e.NewValue;
if (cc != null) cc.OnPropertyChanged(nameof(SelectedItem));
}
public static readonly DependencyProperty DisplayMemberPathProperty =
DependencyProperty.Register("DisplayMemberPath", typeof(string),
typeof(FloatingLabelComboBox), new PropertyMetadata(null));
public string DisplayMemberPath
{
get { return GetValue(DisplayMemberPathProperty).ToString(); }
set { SetValue(DisplayMemberPathProperty, value); }
}
public static readonly DependencyProperty SelectedValueProperty =
DependencyProperty.RegisterAttached("SelectedValue", typeof(object),
typeof(FloatingLabelComboBox),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
new PropertyChangedCallback(OnSelectedValueChanged)));
public object SelectedValue
{
get { return GetValue(SelectedValueProperty); }
set { SetValue(SelectedValueProperty, value); }
}
private static void OnSelectedValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FloatingLabelComboBox cc = d as FloatingLabelComboBox;
cc.SelectedValue = e.NewValue;
if (cc != null) cc.OnPropertyChanged(nameof(SelectedValue));
}
public static readonly DependencyProperty CBConverterProperty =
DependencyProperty.Register("CBConverter", typeof(IValueConverter),
typeof(FloatingLabelComboBox), new PropertyMetadata(null));
public IValueConverter CBConverter
{
get { return (IValueConverter)GetValue(CBConverterProperty); }
set { SetValue(CBConverterProperty, value); }
}
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command", typeof(ICommand),
typeof(FloatingLabelComboBox),
new FrameworkPropertyMetadata(null));
public object Command
{
get { return GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public Visibility CommandVisible { get => (Command == null) ? Visibility.Collapsed : Visibility.Visible; }
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] String propertyName = "")
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public class BoolToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Student st = value as Student;
return (st != null && !string.IsNullOrEmpty(st.BloodGroup)) ? Brushes.LightGreen : Brushes.LightPink;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class RelayCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _action;
public RelayCommand(Action<object> action) { _action = action; _canExecute = null; }
public RelayCommand(Action<object> action, Predicate<object> canExecute) { _action = action; _canExecute = canExecute; }
public void Execute(object o) => _action(o);
public bool CanExecute(object o) => _canExecute == null ? true : _canExecute(o);
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
}
Result: