使用MVVM Light在Silverlight中绑定ComboBox的问题

时间:2010-11-02 13:24:04

标签: silverlight mvvm-light

在Silverlight 4 + MVVM-Light工具包中遇到问题后挣扎了一周,在搜索网络后没有成功,我想在这里提出我的问题并希望有人能给我一些提示。

我想介绍一下简化的程序:

我的模特课程:

  1. 公共类人员 {     private decimal _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 {     private decimal _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; }
    }
    

    }

  3. 这是我的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方法中,为ChoosenPerson对象分配了一个新的PersonInfo实例。当我第二次单击该按钮时会发生此问题。然后作为单击按钮后的参数,我得到一个PersonInfo类的实例,其中包含文本框中正确插入的文本但是在组合框中选择的值我总是得到 0 ,独立于我选择在组合框中。这种问题只发生在我用作类的组合框项实例的情况下。如果我用作组合框项目只是字符串值,则不会发生此问题。但是我必须在我的组合框中使用类的实例。

    我希望有人有提示。 谢谢!

    PS:

    有趣的是,当从“ChoosenPerson = new Model.PersonInfo();”更改ChoosenPerson的赋值时,到 _choosenPerson = new Model.PersonInfo(); 这意味着通过使用私有成员而不是访问方法进行赋值,第二次单击该按钮时,值将正确写入按钮的参数。唯一的事情是不会删除上次插入的值。单击第一个按钮后显示它们。但是当通过访问方法分配新的空ChoosenPerson时,它们不会显示出来...... 我无法解释这种行为。谁能帮我??谢谢。

2 个答案:

答案 0 :(得分:0)

我想你想要这样的东西:

<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的数据上下文,其余的控件就可以简单地引用属性名称,而不必使用Locator。我也认为你有一些事情指向错误的地方。

答案 1 :(得分:0)

亚当走在正确的轨道上。我会将您的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属性需要为null或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);
        }
    }
}