Ok this is just a little example. I used a viewmodel, with InotifyPropertyChanged implemented, a button with a Command binded and triggers on the column of the grid. Here is the working example
As you can see i placed 2 textblock in the inner grid to represent your "cameras"
now the viewmodel
-Viewmodel
namespace WpfApp2
{
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private bool camera1 = false;
private bool camera2 = false;
public bool Camera1
{
get { return camera1; }
set
{
camera1 = true;
NotifyPropertyChanged();
}
}
public bool Camera2
{
get { return camera2; }
set
{
camera2 = true;
NotifyPropertyChanged();
}
}
private RelayCommand addCamera;
private void Add()
{
if (Camera1 == false)
{
Camera1 = true;
}
else
Camera2 = true;
}
public ICommand AddCamera
{
get
{
addCamera = new RelayCommand(() => Add());
return addCamera;
}
}
}
}
If you understand MVVM you shouldn't be surprised by the viewmodel i presented above
as Extra an utility that i use to implement Commands
-Relay Command
namespace WpfApp2
{
internal class RelayCommand<T> : ICommand
{
#region Fields
readonly Action<T> _execute = null;
readonly Predicate<T> _canExecute = null;
#endregion // Fields
#region Constructors
public RelayCommand(Action<T> execute)
: this(execute, null)
{
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Action<T> execute, Predicate<T> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute((T)parameter);
}
public event EventHandler CanExecuteChanged
{
add
{
if (_canExecute != null)
CommandManager.RequerySuggested += value;
}
remove
{
if (_canExecute != null)
CommandManager.RequerySuggested -= value;
}
}
public void Execute(object parameter)
{
_execute((T)parameter);
}
#endregion // ICommand Members
}
/// <summary>
/// A command whose sole purpose is to
/// relay its functionality to other
/// objects by invoking delegates. The
/// default return value for the CanExecute
/// method is 'true'.
/// </summary>
internal class RelayCommand : ICommand
{
#region Fields
readonly Action _execute;
readonly Func<bool> _canExecute;
#endregion // Fields
#region Constructors
/// <summary>
/// Creates a new command that can always execute.
/// </summary>
/// <param name="execute">The execution logic.</param>
public RelayCommand(Action execute)
: this(execute, null)
{
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Action execute, Func<bool> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute();
}
public event EventHandler CanExecuteChanged
{
add
{
if (_canExecute != null)
CommandManager.RequerySuggested += value;
}
remove
{
if (_canExecute != null)
CommandManager.RequerySuggested -= value;
}
}
public void Execute(object parameter)
{
_execute();
}
#endregion // ICommand Members
}
}
Basically everything work around the DataTrigger inserted in the ColumnDefinition style. Note that when you press add camera, the Column will take all the available space thanks to Width = "*", so that every time you add a camera, each one will take the same amount of space. Of course this is just an example and you should work on it to add features like remove camera, add the opposite trigger (to put again the width to 0) etc. , but it's just to give you an idea.
P.S.: Someone will tell you that assign the datacontext as i did, is the biggest mistake you can do in MVVM. I don't agree with this, however, you have to find your way, when working with MVVM and i used datacontext as i did just to write this example faster
Gridand itsColumnDefinitions&RowDefinitions.stackpanel