MVVM绑定组合框

时间:2011-04-10 17:40:58

标签: silverlight mvvm

我有一个非常普通的ViewModel,我想把一组值绑定到一个组合框。问题是没有任何约束力。我检查了ViewModel构造函数,并且正在加载数据,所以我怀疑它在我的XAML中,但我不知道在哪里。

public class OwnerOccupierAccountViewModel : ViewModelBase
{
    readonly UserAccountContext _userAccountContext;
    readonly LoadOperation<Structure> _loadStructures;


    #region Properties

    private ObservableCollection<Structure> _structures;
    public ObservableCollection<Structure> Structures
    {
        get { return _structures; }

        set
        {
            _structures = value;
            RaisePropertyChanged("Structures");
        }
    }

    private Structure _selectedStructure;
    public Structure SelectedStructure
    {
        get { return _selectedStructure; }
        set
        {
            _selectedStructure = value;
            RaisePropertyChanged("SelectedStructure");
        }
    }

    #endregion

    public OwnerOccupierAccountViewModel()
    {
        _userAccountContext = new UserAccountContext();

        if (!DesignerProperties.IsInDesignTool)
        {
            _loadStructures = _userAccountContext.Load(_userAccountContext.GetStructuresQuery());
            _loadStructures.Completed += new EventHandler(_loadStructures_Completed);
        }
    }

    void _loadStructures_Completed(object sender, EventArgs e)
    {
        _structures = new ObservableCollection<Structure>();
        foreach (var structure in _loadStructures.Entities)
        {
            Structures.Add(structure);
        }
    }
}

<UserControl.Resources>
    <viewmodel:OwnerOccupierAccountViewModel x:Key='ViewModel'></viewmodel:OwnerOccupierAccountViewModel>
</UserControl.Resources>

<ComboBox x:Name='cboApartments'
                          ItemsSource='{Binding Structures,Source={StaticResource ViewModel},Mode=TwoWay}'
                          Width='200' />

4 个答案:

答案 0 :(得分:2)

尝试初始化您的ObservableCollection of Structures:

void _loadStructures_Completed(object sender, EventArgs e)
    {
        Structures = new ObservableCollection<Structure>(_loadStructures.Entities);      
    }

正如之前提到的,我认为你应该在这里改变秩序:

if (!DesignerProperties.IsInDesignTool)
{
    //other code before
    //_loadStructures = ...
    _loadStructures.Completed += new EventHandler(_loadStructures_Completed);
   //and now start loading       
}

我做了类似的,非常简单的应用程序,以检查可能出错的地方,但一切正常。我将向您展示我的代码,以便您可以进行比较,也许您会在解决方案中找到一些错误。

Structure.cs

public class Structure
{
    public Structure(string name)
    {
        Name = name;
    }
    public string Name { get; set; }
}

StructureService.cs

public class StructureService
{
    public void GetAllStructures(Action<IList<Structure>> CompleteCallback)
    {
        var temp = new List<Structure>() 
            {
                new Structure("Str1"),
                new Structure("Str2"),
                new Structure("Str3"),
                new Structure("Str4"),
                new Structure("Str5"),
                new Structure("Str6"),
                new Structure("Str7")
            };
        CompleteCallback(temp);
    }
}

ViewModelBase.cs

public class ViewModelBase : INotifyPropertyChanged
{
    protected void RaisePropertyChanged(string prop)
    {
        var temp = PropertyChanged;
        if (temp != null)
        {
            temp(this, new PropertyChangedEventArgs(prop));
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

OwnerOccupierAccountViewModel:

public class OwnerOccupierAccountViewModel : ViewModelBase
{
    StructureService service;
    public OwnerOccupierAccountViewModel()
    {
        if (!DesignerProperties.IsInDesignTool)
        {
            service = new StructureService();
            service.GetAllStructures((result) =>
            {
                Structures = new ObservableCollection<Structure>(result);
            });

        }
    }
    private ObservableCollection<Structure> _structures;
    public ObservableCollection<Structure> Structures
    {
        get { return _structures; }
        set
        {
            _structures = value;
            RaisePropertyChanged("Stuctures");
        }
    }
    private Structure _selectedStructure;
    public Structure SelectedStructure
    {
        get { return _selectedStructure; }
        set
        {
            _selectedStructure = value;
            RaisePropertyChanged("SelectedStructure");
        }
    }
}

MainPage.xaml中:

<UserControl x:Class="SilverlightApplication1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vm="clr-namespace:SilverlightApplication1"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <UserControl.Resources>
        <vm:OwnerOccupierAccountViewModel x:Key="ViewModel"/>
    </UserControl.Resources>
        <Grid x:Name="LayoutRoot" Background="White">
        <ComboBox x:Name="cboApartments"
                          ItemsSource='{Binding Structures,Source={StaticResource ViewModel},Mode=TwoWay}'
                          SelectedItem="{Binding SelectedStructure, Source={StaticResource ViewModel},Mode=TwoWay}"
                          Width="100" Height="30">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Path=Name}"/>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
    </Grid>
</UserControl>

如果我在你的鞋子里,我会将xaml改为这样的观点:

SuggestedView:

<UserControl x:Class="SilverlightApplication1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vm="clr-namespace:SilverlightApplication1"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <UserControl.DataContext>
        <vm:OwnerOccupierAccountViewModel/>
    </UserControl.DataContext>
        <Grid x:Name="LayoutRoot" Background="White">
        <ComboBox x:Name="cboApartments"
                          ItemsSource='{Binding Structures, Mode=TwoWay}'
                          SelectedItem="{Binding SelectedStructure, Mode=TwoWay}"
                          Width="100" Height="30">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Path=Name}"/>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
    </Grid>
</UserControl>

但我明白在你的场景中某种程度上是不可能的? enter image description here

答案 1 :(得分:1)

尝试替换此行:

 _structures = new ObservableCollection<Structure>();

用这个:

Structures = new ObservableCollection<Structure>();

并将ComboBox的绑定设置为OneWay。

编辑更新解决方案:

同时设置ComboBox的DisplayMemberPath属性:

DisplayMemberPath="StructureName"

答案 2 :(得分:1)

只有在更改属性时才会触发绑定。设置后备变量的行不会调用RaisePropertyChanged事件。即使它确实如此,此时它仍然是空的,你最终会得到一个空列表。

_structures = new ObservableCollection<Structure>();

当您添加到集合中时,您没有更改属性值,而是调用getter,因此RaisePropertyChanged将不再触发。

Structures.Add(structure);

您需要构建一个本地集合,然后将其用作Structures属性的值。这应该会导致绑定被触发。

var structures = new ObservableCollection<Structure>();
foreach ...
Structures = structures;

答案 3 :(得分:0)

您是直接绑定到ViewModel键作为源,但它是否在任何地方设置为DataContext?