简体   繁体   English

属性未正确绑定在ListBox DataTemplate中

[英]Property not bound correctly in ListBox DataTemplate

I've been having some trouble getting a listbox to correctly bind to a collection. 我在获取列表框以正确绑定到集合时遇到了一些麻烦。

I'll give the framework code, then explain what I want it to do. 我将提供框架代码,然后解释我想要它做什么。

XAML Markup: 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: 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# Model: C#模型:

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

My problem is that any changes to the textboxes for the strings in the Bar collection aren't set. 我的问题是,未设置Bar集合中字符串的文本框的任何更改。 When the selected Foo changes to a different Foo and back, the original Bars are displayed. 当选定的Foo更改为其他Foo并返回时,将显示原始Bars

Could someone tell me what I'm doing wrong? 有人能告诉我我做错了什么吗? This seems like it should be much more simple. 这似乎应该更简单。 Thanks! 谢谢!

Update: I've changed the code as per Tri Q's suggestion, but the changes made to the textbox aren't reflected in the property itself. 更新:我已经按照Tri Q的建议更改了代码,但是对文本框所做的更改未反映在属性本身中。 Any ideas? 有任何想法吗?

Your Foo model class I take has been simplified for this example, but the omitted code could be the culprit of your problem. 在本示例中,我采用的Foo模型类已得到简化,但是省略的代码可能是导致问题的根源。 Let me explain. 让我解释。

Foo also needs to implement INotifyPropertyChanged to let the Listbox know when you have initialized the Bars collection and this most definitely depends on when you are initializing it. Foo还需要实现INotifyPropertyChanged,以便在初始化Bars集合时让Listbox知道,而这绝对取决于初始化它的时间。

Say you initialize Bars in Foo's constructor will cause the Listbox ItemsSource to bind to a valid Bars collection. 假设您在Foo的构造函数中初始化Bars,将导致Listbox ItemsSource绑定到有效的Bars集合。

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

Buut if you did something like this, the Listbox will not know that the Bars collection has been initialized and will not update it's source... Buut,如果您这样做,列表框将不知道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>();
            // ...
        }
    }
}

Also here are a few things you might want to revise in your XAML. 另外,您可能需要在XAML中进行一些修改。

Firstly, binding of the Textbox is TwoWay by default, so you do not need to set the Mode or the Path . 首先,默认情况下, Textbox绑定为TwoWay ,因此您无需设置ModePath

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

Secondly, it makes no sense to set Mode="TwoWay" for ItemsSource . 其次,为ItemsSource设置Mode="TwoWay"没有意义。 ItemsSource="{Binding Main.SelectedFoo.Bars , Mode=TwoWay }" ItemsSource =“ {Binding Main.SelectedFoo.Bars ,Mode = TwoWay }”

Finally, you don't need to set the DataType for your DataTemplate . 最后,您不需要为DataTemplate设置DataType DataType="{x:Type System:String}" DataType =“ {x:Type系统:字符串}”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM