I am very new to MVVM and I am stuck with data binding. I have a button on my view page which dynamically creates text boxes but I cannot see how I bind these textboxes to my List in ViewModel.
In my view i have:
<Button x:Name="btWebsite" Grid.ColumnSpan="2" Width="50" Height="50" Click="btWebsite_Click" Margin="23,245,259,202">
<StackPanel x:Name="pnWebsiteButton" Orientation="Horizontal">
<Image x:Name="imgWebsite" Source= "Images/webIcon.jpg" Stretch="Fill" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</StackPanel>
</Button>
<GroupBox x:Name="grpWebsite" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="73,245,0,0" Grid.ColumnSpan="2" Height="51" Width="170" BorderBrush="{x:Null}" BorderThickness="0">
<ScrollViewer x:Name="pnScrollWebsite" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Margin="0,0,0,-6">
<StackPanel x:Name="pnWebsite" Orientation="Vertical" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="1,2,0,0" VerticalAlignment="Top" IsEnabled="True">
</StackPanel>
</ScrollViewer>
</GroupBox>
The code behind the button is:
private void btWebsite_Click(object sender, RoutedEventArgs e)
{
var newTextBox = new TextBox();
newTextBox.Text = "type the website address...";
newTextBox.Foreground = Brushes.Gray;
newTextBox.Width = 150;
newTextBox.Name = "txtWebsite" + iWebsites;
pnWebsite.Children.Add(newTextBox);
pnWebsite.RegisterName(newTextBox.Name, newTextBox);
iWebsites++;
}
In my ViewModel i have:
public List<string> Websites
{
get { return _websites; }
set
{
if (value != _websites)
{
_websites = value;
OnPropertyChanged("Websites");
}
}
}
I am struggling to see how I get the website textboxes into the viewmodel list. Thank you for your help
Delete your event handler from the code-behind: btWebsite_Click.
Modify your xaml like this:
<Button x:Name="btWebsite" Grid.ColumnSpan="2" Width="50" Height="50" Command="{Binding AddNewStringCommand}" Margin="23,245,259,202">
<StackPanel x:Name="pnWebsiteButton" Orientation="Horizontal">
<Image x:Name="imgWebsite" Source= "Images/webIcon.jpg" Stretch="Fill" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</StackPanel>
</Button>
<GroupBox x:Name="grpWebsite" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="73,245,0,0" Grid.ColumnSpan="2" Height="51" Width="170" BorderBrush="{x:Null}" BorderThickness="0">
<ScrollViewer x:Name="pnScrollWebsite" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Margin="0,0,0,-6">
<StackPanel x:Name="pnWebsite" Orientation="Vertical" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="1,2,0,0" VerticalAlignment="Top" IsEnabled="True">
<ItemsControl ItemsSource="{Binding Websites}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Mode=TwoWay}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</GroupBox>
You need to modify your ViewModel also:
public ObservableCollection<string> Websites { get; set; }
public ICommand AddNewStringCommand => new RelayCommand(AddNewString);
private void AddNewString()
{
Websites.Add(string.Empty);
}
Instead of RelayCommand
you can use any implementation of ICommand
. I use for example MVVMLight.
As you see, the main differences:
Update:
I made a mistake, ObservableCollection is not working directly with the TextBox.
It seems you need something in addition:
public class Website
{
public string Name { get; set; }
}
Modify the ViewModel like this:
public ObservableCollection<Website> Websites { get; set; } = new ObservableCollection<Website>();
public ICommand AddNewStringCommand => new RelayCommand(AddNewString);
private void AddNewString()
{
Websites.Add(new Website {Name = "new website"});
}
And the ItemsTemplate like this:
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel >
<TextBox Text="{Binding Name, Mode=TwoWay}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With