动态将文本框绑定到列表

6

我很新于MVVM,目前遇到了数据绑定的问题。我的视图页面上有一个按钮,它可以动态地创建文本框,但我不知道如何将这些文本框与ViewModel中的List进行绑定。

在我的视图中,我有以下代码:

<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>
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++;
}

在我的ViewModel中,我有:
public List<string> Websites
{
    get { return _websites; }
    set
    {
        if (value != _websites)
        {
            _websites = value;
            OnPropertyChanged("Websites");
        }
    }
}

我很难理解如何将网站文本框添加到视图模型列表中。谢谢您的帮助。


1
更好的做法是使用绑定到Websites集合的ItemsControl<ItemsControl ItemsSource="{Binding Path=Websites}"/>。将Websites设置为ObservableCollection<string>,向集合中添加字符串 - 它将在视图中显示。 - ASh
你可以顺便去一下WPF聊天室。我们主要关注MVVM在WPF中的应用。注意:你需要至少15个声望才能在那里发言。 - Lynn Crumbling
你现在应该没问题了。 - Lynn Crumbling
系统仍在告诉您,您的声望不足吗? - Lynn Crumbling
让我们在聊天中继续这个讨论 - Theresa Ferguson
显示剩余3条评论
1个回答

1
从代码后台中删除事件处理程序:btWebsite_Click。
将您的xaml修改为以下内容:
<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>

您需要修改您的ViewModel:

public ObservableCollection<string> Websites { get; set; }

public ICommand AddNewStringCommand => new RelayCommand(AddNewString);

private void AddNewString()
{
    Websites.Add(string.Empty);
}

你可以使用实现了ICommand接口的任何类,而不仅仅是RelayCommand。例如我使用MVVMLight。

如你所见,主要区别有:

  • 按钮中没有处理Click事件,而是使用命令绑定。
  • 不需要从代码后台生成新的控件,而是使用ItemsControl在每次有新元素添加到集合时自动创建一个控件。
  • 新的TextBox的Text属性与新元素进行绑定。

更新:

我犯了一个错误,ObservableCollection不能直接与TextBox一起使用。

看起来你需要额外的东西:

public class Website
{
    public string Name { get; set; }
}

将ViewModel修改为以下内容:
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"});
}

并且ItemsTemplate如下:

<ItemsControl.ItemTemplate>
    <DataTemplate>
        <StackPanel >
            <TextBox Text="{Binding Name, Mode=TwoWay}"/>
        </StackPanel>
    </DataTemplate>
</ItemsControl.ItemTemplate>

谢谢,看起来不错。我已经实现了你的建议,但是现在新的文本框没有显示在页面上。 - Theresa Ferguson
@TheresaFerguson 我添加了一些更新,因为我测试过了,它没有正常工作。 - dvjanm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接