属性未在ListBox DataTemplate中正确绑定

时间:2010-10-04 21:06:22

标签: c# wpf data-binding mvvm mvvm-light

我在使列表框正确绑定到集合时遇到了一些麻烦。

我将给出框架代码,然后解释我希望它做什么。

XAML加价:

<ListBox DataContext="{Binding Foos, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                       ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True" 
                       SelectedItem="{Binding Main.SelectedFoo, Mode=TwoWay, 
                       Source={StaticResource Locator}, 
                       UpdateSourceTrigger=PropertyChanged}" 
                       SelectedValue="{Binding Main.SelectedFoo, Source={StaticResource Locator}}"/>


<ListBox ItemsSource="{Binding Main.SelectedFoo.Bars}"  SelectedItem="{Binding Main.SelectedBar}"  >
<ListBox.ItemTemplate>
    <DataTemplate>
        <Grid HorizontalAlignment="Right">
            <!-- The binding requires "{Binding .}" because a path must be explicitly set for Two-Way binding,
                 even though {Binding .} is supposed to be identical to {Binding} -->
                <TextBox Text="{Binding Path=. , UpdateSourceTrigger=PropertyChanged}"  />
         </Grid>
    </DataTemplate>
</ListBox.ItemTemplate>

C#ViewModel:

private ObservableCollection<Foo> _barList = new ObservableCollection<Foo>();
private const string BardListPN = "FooList";

public ObservableCollection<Foo> FooList
{
    get { return _fooList; }

    set
    {
        if (_fooList == value)
        {
            return;
        }

        var oldValue = _fooList;
        _fooList = value;

        RaisePropertyChanged(FooListPN);
    }
}

private Foo _selectedFoo;
private const string SelectedFooPN = "SelectedFoo";

public Foo SelectedFoo
{
    get { return _selectedFoo; }

    set
    {
        if (_selectedFoo == value)
        {
            return;
        }

        var oldValue = _selectedFoo;
        _selectedFoo = value;

        // Update bindings, no broadcast
        RaisePropertyChanged(SelectedFooPN);
    }
}

public const string SelectedBarPN = "SelectedBar";
private string _selectedBar = "";

public string SelectedBar
{
    get
    {
        return _selectedBar;
    }

    set
    {
        if (_selectedBar == value)
        {
            return;
        }

        var oldValue = _selectedBar;
        _selectedBar = value;


        // Update bindings, no broadcast
        RaisePropertyChanged(SelectedBarPN);
    }
}

C#型号:

public class Foo
{
    public ICollection<string> Bars
    {
        get { return _bars; }
        set
        {
            _bars= value;
            NotifyPropertyChanged("Bars"); 
            // snipped obvious INotifyPropertyChanged boilerplate code
        }
    }
}

我的问题是没有设置Bar集合中字符串的文本框的任何更改。当选定的Foo更改为其他Foo并返回时,会显示原始Bars

有人能告诉我我做错了什么吗?这似乎应该简单得多。谢谢!

更新:我已根据Tri Q的建议更改了代码,但对文本框所做的更改未反映在属性本身中。有什么想法吗?

1 个答案:

答案 0 :(得分:2)

我为此示例简化了我的Foo模型类,但省略的代码可能是您问题的罪魁祸首。让我解释一下。

Foo还需要实现INotifyPropertyChanged,让Listbox知道你何时初始化了Bars集合,这绝对取决于你何时初始化它。

假设您在Foo的构造函数中初始化Bars将导致Listbox ItemsSource绑定到有效的Bars集合。

public Foo()
{
    Bars = new ObservableCollection<string>();
    ...
}

如果你做了类似的事情,那么Listbox将不会知道Bars集合已经初始化并且不会更新它的源代码......

public Foo SelectedFoo
{
    get { return _selectedFoo; }

    set
    {
        if (_selectedFoo == value)
        {
            return;
        }

        var oldValue = _selectedFoo;
        _selectedFoo = value;

        // Update bindings, no broadcast
        RaisePropertyChanged(SelectedFooPN);

        if(_selectedFoo.Bars == null)
        {
            _selectedFoo.Bars = new ObservableCollection<string>();
            // ...
        }
    }
}

此外,您可能需要在XAML中修改一些内容。

首先,Textbox的绑定默认为TwoWay,因此您无需设置ModePath

<TextBox Text="{Binding UpdateSourceTrigger=PropertyChanged}"  />

其次,为Mode="TwoWay"设置ItemsSource是没有意义的。 ItemsSource =“{Binding Main.SelectedFoo.Bars ,Mode = TwoWay }”

最后,您无需为DataType设置DataTemplate DataType =“{x:Type System:String}”