Проблема с привязкой данных ComboBox в Silverlight с MVVM Light - PullRequest
1 голос
/ 02 ноября 2010

После одной недели борьбы с проблемой в наборе инструментов Silverlight 4 + MVVM-Light и безуспешного поиска в Интернете я хочу изложить здесь свою проблему и надеюсь, что кто-нибудь может дать мне несколько советов.

Я хочу представить упрощенную программу:

Мои классы моделей:

  1. лицо

    человек публичного класса { частный десятичный _cod_Person;

    public decimal Cod_Person
    {
        get { return _cod_Person; }
        set { _cod_Person = value; }
    }
    private string _des_Person;
    
    
    public string Des_Person
    {
        get { return _des_Person; }
        set { _des_Person = value; }
    }
    

    }

  2. PersonInfo

    открытый класс PersonInfo { частный десятичный _cod_person;

    public decimal Cod_person
    {
        get { return _cod_person; }
        set { _cod_person = value; }
    }
    private string _des_note;
    
    
    public string Des_note
    {
        get { return _des_note; }
        set { _des_note = value; }
    }
    

    }

Вот моя ViewModel:

public class PersonViewModel : ViewModelBase
{
    public RelayCommand<Model.PersonInfo> save_Click { get; private set; }

    public PersonViewModel()
    {
        save_Click = new RelayCommand<Model.PersonInfo>(personInfo =>
        {
            SavePerson(personInfo);
        });
        //the content of the combo box is defined
        AllPerson = new ObservableCollection<Model.Person>
        {
            new Model.Person(){
                Cod_Person = 1,
                Des_Person = "Name 1"
            },
            new Model.Person(){
                Cod_Person = 2,
                Des_Person = "Name 2"
            }
        };

        //an empty PersonInfo is created, which the UI will work on
        ChoosenPerson = new Model.PersonInfo();
    }

    private void SavePerson(Model.PersonInfo personInfo)
    {
        //here some safing processing could be done...
        //but is omitted here


        //and here a new PersonInfo is assigned the ChoosenPerson
        ChoosenPerson = new Model.PersonInfo();
    }

    public const string AllPersonPropertyName = "AllPerson";
    private ObservableCollection<Model.Person> _allPersons = null;
    public ObservableCollection<Model.Person> AllPerson
    {
        get
        {
            return _allPersons;
        }

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

            var oldValue = _allPersons;
            _allPersons = value;
            RaisePropertyChanged(AllPersonPropertyName, oldValue, value, true);
        }
    }

    public const string ChoosenPersonPropertyName = "ChoosenPerson";
    private Model.PersonInfo _choosenPerson = null;
    public Model.PersonInfo ChoosenPerson
    {
        get
        {
            return _choosenPerson;
        }

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

            var oldValue = _choosenPerson;
            _choosenPerson = value;

            // Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
            RaisePropertyChanged(ChoosenPersonPropertyName, oldValue, value, true);
        }
    }
}

На мой взгляд (PersonView) у меня есть поле со списком, текстовое поле и кнопка:

<UserControl x:Class="TEST_STACKOVERFLOW.PersonView"
         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"
         mc:Ignorable="d"
         DataContext="{Binding Source={StaticResource Locator}, Path=PersonViewModel.ChoosenPerson}" d:DesignHeight="258" d:DesignWidth="341">
<Grid>
    <ComboBox Height="23" HorizontalAlignment="Left" Margin="84,51,0,0" Name="comboBox1" VerticalAlignment="Top" Width="120" ItemsSource="{Binding Source={StaticResource Locator}, Path=PersonViewModel.AllPerson}" DisplayMemberPath="Des_Person" SelectedValuePath="Cod_Person" SelectedValue="{Binding Path=Cod_person, Mode=TwoWay}" />
    <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="159,199,0,0" Name="button1" VerticalAlignment="Top" Width="75" Command="{Binding Source={StaticResource Locator}, Path=PersonViewModel.save_Click}" CommandParameter="{Binding}" />
    <TextBox Height="23" HorizontalAlignment="Left" Margin="94,107,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding Path=Des_note, Mode=TwoWay}" />
</Grid>

При первом нажатии кнопки все работает. Параметр (PersonInfo), передаваемый после нажатия кнопки, содержит выбранное значение ComboBox (Cod_person) и вставленный текст (Des_note). В методе SavePerson новый экземпляр PersonInfo назначается объекту ChoosenPerson. Проблема возникает, когда я нажимаю кнопку во второй раз. Затем в качестве параметра после нажатия кнопки я получаю экземпляр класса PersonInfo, который содержит правильный вставленный текст в текстовом поле, но в качестве значения, выбранного в поле со списком, я всегда получаю 0 , независимо от того, что я выбрал в поле со списком. Эта проблема возникает только в том случае, если я использую в качестве элементов списка со списком экземпляры класса. Если я использую в качестве элементов поля со списком только строковые значения, эта проблема не возникает. Но я должен использовать экземпляры класса в поле со списком.

Я надеюсь, что у кого-то есть подсказка. Спасибо!

PS:

Интересным остается тот факт, что при изменении назначения ChoosenPerson с «ChoosenPerson = new Model.PersonInfo ();» to _choosenPerson = new Model.PersonInfo (); это означает, что при присваивании с использованием закрытых членов вместо методов доступа при втором нажатии кнопки значения записываются в параметр кнопки правильно. Единственное, что значения, которые были вставлены в последний раз, не удаляются. Они отображаются после первого нажатия кнопки. Но они не отображаются, когда назначение нового пустого ChoosenPerson осуществляется через методы доступа ... Я не могу объяснить это поведение. Кто может мне помочь?? Спасибо.

Ответы [ 2 ]

0 голосов
/ 02 ноября 2010

Адам был на правильном пути.Я бы назначил ваш PersonViewModel на DataContext вместо того, чтобы назначать его на ChoosenPerson.

<UserControl
    x:Class="TEST_STACKOVERFLOW.PersonView"
    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"
    DataContext="{Binding Source={StaticResource Locator}, Path=PersonViewModel}"
    mc:Ignorable="d" d:DesignHeight="258" d:DesignWidth="341">

    <Grid>
        <ComboBox Height="23" HorizontalAlignment="Left" Margin="84,51,0,0" Name="comboBox1" VerticalAlignment="Top" Width="120" ItemsSource="{Binding AllPerson}" DisplayMemberPath="Des_Person" SelectedValuePath="Cod_Person" SelectedItem="{Binding Path=ChoosenPerson, Mode=TwoWay}" />
        <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="159,199,0,0" Name="button1" VerticalAlignment="Top" Width="75" Command="{Binding save_Click}" CommandParameter="{Binding SelectedItem, ElementName=comboBox1}" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="94,107,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding ChoosenPerson.Des_Person, Mode=TwoWay}" />
    </Grid>
</UserControl>

Я бы также полностью избавился от класса PersonInfo.Вам не нужен этот класс.Вы можете работать с объектом Person напрямую.Измените ваши ссылки с PersonInfo на Person класс.Кроме того, если вы хотите очистить текущий выбор в ComboBox, установите для свойства ChoosenPerson значение null.Не создавайте новый экземпляр класса.Свойство ChoosenPerson должно быть либо нулевым, либо одним из объектов в коллекции AllPerson.

public class PersonViewModel : ViewModelBase
{
    public RelayCommand<Person> save_Click { get; private set; }

    public PersonViewModel()
    {
        save_Click = new RelayCommand<Person>(personInfo =>
        {
            SavePerson(personInfo);
        });

        //the content of the combo box is defined
        AllPerson = new ObservableCollection<Person>
        {
            new Person(){
                Cod_Person = 1,
                Des_Person = "Name 1"
            },
            new Person(){
                Cod_Person = 2,
                Des_Person = "Name 2"
            }
        };

        //an empty PersonInfo is created, which the UI will work on
        ChoosenPerson = new Person();
    }

    private void SavePerson(Person personInfo)
    {
        //here some safing processing could be done...
        //but is omitted here


        //and here a new PersonInfo is assigned the ChoosenPerson
        ChoosenPerson = null;
    }

    public const string AllPersonPropertyName = "AllPerson";
    private ObservableCollection<Person> _allPersons = null;
    public ObservableCollection<Person> AllPerson
    {
        get
        {
            return _allPersons;
        }

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

            var oldValue = _allPersons;
            _allPersons = value;
            RaisePropertyChanged(AllPersonPropertyName, oldValue, value, true);
        }
    }

    public const string ChoosenPersonPropertyName = "ChoosenPerson";
    private Person _choosenPerson = null;
    public Person ChoosenPerson
    {
        get
        {
            return _choosenPerson;
        }

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

            var oldValue = _choosenPerson;
            _choosenPerson = value;

            // Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
            RaisePropertyChanged(ChoosenPersonPropertyName, oldValue, value, true);
        }
    }
}
0 голосов
/ 02 ноября 2010

Я думаю, вы хотите что-то вроде этого:

<UserControl x:Class="TEST_STACKOVERFLOW.PersonView" 
         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" 
         mc:Ignorable="d" 
         DataContext="{Binding Source={StaticResource Locator}, Path=PersonViewModel}" d:DesignHeight="258" d:DesignWidth="341"> 
<Grid> 
    <ComboBox Height="23" HorizontalAlignment="Left" Margin="84,51,0,0" Name="comboBox1" VerticalAlignment="Top" Width="120" ItemsSource="{Binding AllPerson}" DisplayMemberPath="Des_Person" SelectedValuePath="Cod_Person" SelectedValue="{Binding Path=ChoosenPerson, Mode=TwoWay}" /> 
    <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="159,199,0,0" Name="button1" VerticalAlignment="Top" Width="75" Command="{Binding save_Click}" CommandParameter="{Binding ChoosenPerson}" /> 
    <TextBox Height="23" HorizontalAlignment="Left" Margin="94,107,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding Path=Des_note, Mode=TwoWay}" /> 
</Grid>

Я обновил большинство привязок. Как только вы установите контекст данных UserControl, остальные элементы управления внутри могут просто ссылаться на имя свойства, вместо того, чтобы использовать Локатор. Я также думаю, что у вас было несколько вещей, указывающих на неправильные места.

...