2010-10-04 66 views
0

我一直有一些麻烦,获得一个列表框正确绑定到集合。属性在列表框DataTemplate中没有正确绑定

我给框架代码,然后解释我想要它做什么。

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#视图模型:

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的建议更改了代码,但对文本框所做的更改未反映在属性本身中。有任何想法吗?

回答

2

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

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

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

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

Buut,如果你做了这样的事情,列表框将不知道该酒吧集合已被初始化,并不会更新它的源...

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 = “{结合Main.SelectedFoo.Bars ,模式=双向 }”

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

+0

太棒了!非常感谢额外的信息。是的,正如你可以清楚地看到的,我仍然在学习WPF和MVVM,并且我衷心感谢评论。我会试试你的建议。 – llaughlin 2010-10-05 12:36:25

+0

需要注意的一件事:我有'TextBox'绑定的方式,因为模式是'TwoWay'(甚至默认),所以需要路径,我在我的XAML注释中注明了这一点。这似乎是将'TextBox'绑定到集合中的当前项目的唯一方法。 – llaughlin 2010-10-05 15:53:26

相关问题