МВВМ Обвязка комбобокс - PullRequest
       1

МВВМ Обвязка комбобокс

1 голос
/ 10 апреля 2011

У меня очень обычный 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 ]

2 голосов
/ 10 апреля 2011

Попробуйте инициализировать вашу 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 на такойпросмотр:

Предложенный просмотр:

<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 голос
/ 10 апреля 2011

Привязка будет срабатывать только при изменении свойства. Строка, устанавливающая переменную поддержки, не будет вызывать событие RaisePropertyChanged. Даже если бы это было так, в любом случае это было бы пусто, и в итоге вы бы получили пустой список.

_structures = new ObservableCollection<Structure>();

Когда вы добавляете в коллекцию значение свойства, которое вы не изменяете, вы вызываете метод получения, поэтому снова RaisePropertyChanged не будет запускаться.

Structures.Add(structure);

Вам необходимо создать локальную коллекцию, а затем использовать ее в качестве значения для свойства Structures. Это должно привести к срабатыванию привязки.

var structures = new ObservableCollection<Structure>();
foreach ...
Structures = structures;
1 голос
/ 10 апреля 2011

Попробуйте заменить эту строку:

 _structures = new ObservableCollection<Structure>();

с этим:

Structures = new ObservableCollection<Structure>();

И установите привязку ComboBox к OneWay.

Отредактировано для обновления решения:

Также установите свойство DisplayMemberPath ComboBox:

DisplayMemberPath="StructureName"
0 голосов
/ 11 апреля 2011

Вы привязываетесь непосредственно к ключу ViewModel в качестве источника, но он где-нибудь установлен как DataContext?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...