Reputation: 4125
I have a user control with a TextBox (Y) and a Button, in my MainWindow(Y) there is another TextBox. When you press the Button a message pops-up and shows us the product X*Y.
Right now if I just simply insert via XAML another as it's bound to some data both UserControl, the original and the just added displays the same (because as I said the TextBox.Text is bound).
What I want is to know how could I extend this and add several UserControl in my MainWindow, so I could type different values in each UserControl and then press the Button and see how much is each product.
RootViewMode.cs
public class RootViewModel : INotifyPropertyChanged
{
#region Implementation of INotifyPropertyChanged
private double _x;
private double _y;
public double X
{
get { return _x; }
set
{
_x = value;
OnPropertyChanged("X");
}
}
public double Y
{
get { return _y; }
set
{
_y = value;
OnPropertyChanged("Y");
}
}
public double XY
{
get { return _x * _y; }
}
}
UserControl1.xaml
<StackPanel>
<Label Content="Y:" />
<TextBox Text="{Binding Path=Y, UpdateSourceTrigger=PropertyChanged, FallbackValue=1}" Margin="5" />
<Button Content="Press me" Click="OnButtonClick" />
</StackPanel>
UserControl1.xaml.cs
private void OnButtonClick(object sender, RoutedEventArgs e)
{
var viewModel = (RootViewModel)DataContext;
var resultMessage = string.Format("{0} * {1} = {2}", viewModel.X, viewModel.Y, viewModel.XY);
MessageBox.Show(resultMessage, "X * Y");
}
MainWindow.xaml
<StackPanel>
<Label Content="X:" />
<TextBox Text="{Binding Path=X, UpdateSourceTrigger=PropertyChanged}" Margin="5" Height="24" />
<WpfApplication22:UserControl1 Margin="5" />
<WpfApplication22:UserControl1 Margin="5" />
</StackPanel>
Of course that inserting the UserControl this way I obtain not desired results. I suspect that I have to create a new RootViemModel for each UserControl, but this has to be done dynamically. I don't want just 2 UserControl but a way to generate them, maybe with a Button that says "Create UserControl!". Thanks.
(Thanks to sevenate for helping me with the code)
Upvotes: 2
Views: 88
Reputation: 44038
You need an ItemsControl
for that:
<Window x:Class="MiscSamples.UserControlItemsControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="UserControlItemsControl" Height="300" Width="300">
<DockPanel>
<StackPanel DockPanel.Dock="Top">
<Label Content="X:"/>
<TextBox Text="{Binding X}"/>
<Button Content="Add User Control" Command="{Binding AddUserControlCommand}"/>
</StackPanel>
<ItemsControl ItemsSource="{Binding Children}">
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer CanContentScroll="True">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- Here you can place your local:UserControl. I just thrown the UI elements -->
<GroupBox Header="User Control">
<StackPanel>
<Label Content="Y:"/>
<TextBox Text="{Binding Y}"/>
<Button Content="Press Me!" Command="{Binding PressMeCommand}"/>
</StackPanel>
</GroupBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DockPanel>
</Window>
Code Behind:
public partial class UserControlItemsControl : Window
{
public UserControlItemsControl()
{
InitializeComponent();
DataContext = new RootViewModel();
}
}
RootViewModel:
public class RootViewModel: PropertyChangedBase
{
private double _x;
public double X
{
get { return _x; }
set
{
_x = value;
OnPropertyChanged("X");
}
}
public ObservableCollection<UserControlViewModel> Children { get; set; }
public Command AddUserControlCommand { get; set; }
public RootViewModel()
{
Children = new ObservableCollection<UserControlViewModel>();
AddUserControlCommand = new Command(AddUserControl);
}
private void AddUserControl()
{
var child = new UserControlViewModel();
child.PressMeCommand = new Command(() => OnUserControlPressed(child));
Children.Add(child);
}
private void OnUserControlPressed(UserControlViewModel item)
{
if (item != null)
{
var xy = X * item.Y;
var resultMessage = string.Format("{0} * {1} = {2}", X, item.Y, xy);
MessageBox.Show(resultMessage, "X * Y");
}
}
}
UserControlViewModel:
public class UserControlViewModel:PropertyChangedBase
{
private double _y;
public double Y
{
get { return _y; }
set
{
_y = value;
OnPropertyChanged("Y");
}
}
public Command PressMeCommand { get; set; }
}
Command class (To avoid using click event handlers where they don't belong):
//Dead-simple implementation of ICommand
//Serves as an abstraction of Actions performed by the user via interaction with the UI (for instance, Button Click)
public class Command : ICommand
{
public Action Action { get; set; }
public void Execute(object parameter)
{
if (Action != null)
Action();
}
public bool CanExecute(object parameter)
{
return IsEnabled;
}
private bool _isEnabled = true;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
}
public event EventHandler CanExecuteChanged;
public Command(Action action)
{
Action = action;
}
}
public class Command<T>: ICommand
{
public Action<T> Action { get; set; }
public void Execute(object parameter)
{
if (Action != null && parameter is T)
Action((T)parameter);
}
public bool CanExecute(object parameter)
{
return IsEnabled;
}
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
}
public event EventHandler CanExecuteChanged;
public Command(Action<T> action)
{
Action = action;
}
}
Result:
Upvotes: 3