在ItemsControl ItemTemplate内绑定到TextBox

3
我的ItemsControl的ItemsTemplate绑定不起作用。我查看了一些类似的Stack Overflow问题,但是我无法找出绑定的问题所在。请问有谁能告诉我我的绑定有什么错误吗?
以下是我的MainWindow的ViewModel的摘录;
private ObservableCollection<uint> words;
private uint word;
private int numberOfWords;

public ObservableCollection<uint> Words
{
    get
    {
        return this.words;
    }

    set
    {
        this.words = value;

        this.NotifyPropertyChanged(m => m.Words);
    }
}

public uint Word
{
    get
    {
        return this.word;
    }

    set
    {
        this.word = value;

        this.NotifyPropertyChanged(m => m.Word);
    }
}

public int NumberOfWords
{
    get
    {
        return this.numberOfWords;
    }

    set
    {
        this.numberOfWords = value;

        this.NotifyPropertyChanged(m => m.NumberOfWords);

        this.Words.Clear();

        for (uint x = 0; x < value; x++)
        {
            this.Words.Add(this.Word);
        }
    }
}

我在一个用户控件中有以下的ItemsControl。MainWindow将其DataContext设置为ViewModel,而ItemsControl使用该ViewModel。ItemsSource绑定可以工作,并且我可以得到所指定的文本框数量,但是当我在TextBox中输入值时,绑定不起作用。

<ItemsControl Grid.Row="0" Grid.Column="1" Grid.RowSpan="8" ItemsSource="{Binding Words}">
<ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
        <WrapPanel />
    </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>

<ItemsControl.ItemTemplate>
    <DataTemplate>
        <TextBox Text="{Binding Word}" Width="125" Height="25" />
    </DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

我看到一个帖子讨论了如何使用下面这种绑定方式,但是显然我不理解FindAncestor,所以我不知道是否走在正确的道路上。

Text="{Binding Path=Word, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}"

Word 属性看起来像是被选中的项目。你为什么想要将每个 TextBox.Text 绑定到同一个属性上?你是不是想要使用 <TextBox Text="{Binding}" Width="125" Height="25" />?这会将 TextBox 绑定到每个项目上。 - dkozl
我确实想将每个文本框的绑定设置为每个项目,但不理解绑定方面的内容。但当我更改我的TextBox绑定并运行它时,设置NumberOfWords属性时出现以下错误:双向绑定需要Path或XPath。 - Wannabe Coder
@dkozl 看起来在视图上它工作了,因为现在每个文本框中都有一个零。但是当我输入值时,我仍然没有看到属性Word被触发,即使我在那里设置了断点。当我检查我的属性Words时,我也没有看到任何变化。 - Wannabe Coder
嗯,我正在尝试理解和修复我的各种问题@Will。这是我第一次使用ItemControl并尝试理解它。你说的话确实有道理。我会重新设计我的视图并看看能从中得到什么。谢谢。 - Wannabe Coder
因为你没有绑定到 Word,而是绑定到每个项目。每个列表只有一个 Word 属性,但你有多个 TextBox,不过我忽略了它是 uint,@Will 是正确的。如果你更改 TextBox,它不会更新集合中的元素。 - dkozl
显示剩余3条评论
1个回答

4

你无法将集合中的元素绑定后再更改该元素本身 - 只能通过绑定更改该元素的属性。换句话说,给定以下集合:

[ "one", "two", "three" ]

通过绑定,例如:

<TextBox Text="{Binding Words[0]} /> <!-- the word "one" is displayed in the tb -->

如果你将 "one" 改为 "derp",你不会改变集合:

[ "derp", "two", "three" ]

将此应用到您的示例中,您需要将集合绑定到 ItemsControl,然后在模板中绑定到集合中的每个实例并更改该实例的属性。
首先,创建您的模型。这将保存您的数据并在 UI 中进行绑定。
public sealed class Word 
{ 
    public uint Value {get;set;}
}

接下来,在您的视图模型中公开这些集合。
public sealed class ViewModel
{
    //create and fill in ctor
    public ObservableCollection<Word> WordsYo {get;private set;}
}

接下来,将你的ItemsControl的ItemsSource属性绑定到该属性,并将模板中的元素绑定到Word的属性。
<!-- Window.DataContext is set to an instance of ViewModel -->
<ItemsControl ItemsSource="{Binding WordsYo}">
<ItemsControl.ItemTemplate>
    <DataTemplate>
        <TextBox Text="{Binding Value}" />
    </DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

贵族们。

非常好!谢谢您这样解释……让我很容易理解。 - Wannabe Coder

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