使用 MVVM Light 在 Silverlight 中对组合框进行数据绑定的问题

发布于 2024-09-30 10:37:14 字数 5009 浏览 2 评论 0原文

在与 Silverlight 4 + MVVM-Light 工具包中的问题斗争了大约一周之后,在网上搜索但没有成功之后,我想在这里提出我的问题,并希望有人能给我一些提示。

我想展示简化的程序:

我的模型类:

  1. Person

    公共类人 { 私有小数_cod_Person;

    公共十进制 Cod_Person
    {
        获取{返回_cod_Person; }
        设置 { _cod_Person = 值; }
    }
    私有字符串_des_Person;
    
    
    公共字符串 Des_Person
    {
        得到{返回_des_Person; }
        设置 { _des_Person = 值; }
    }
    

    }

  2. 人员信息

    公共类PersonInfo { 私人小数_cod_person;

    公共十进制 Cod_person
    {
        得到{返回_cod_person; }
        设置 { _cod_person = 值; }
    }
    私有字符串_des_note;
    
    
    公共字符串 Des_note
    {
        得到{返回_des_note; }
        设置 { _des_note = 值; }
    }
    

    }

是我的 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 = new Model.PersonInfo();”更改 ChoosenPerson 的分配时to _choosenPerson = new Model.PersonInfo(); 这意味着通过使用私有成员而不是访问方法进行分配,第二次单击按钮时,值将正确写入按钮的参数中。唯一的问题是上次插入的值没有被删除。它们在第一次单击按钮后显示。但是当通过访问方法分配新的空 ChoosenPerson 时,它们不会显示...... 我无法解释这种行为。谁能帮助我?谢谢。

After struggling for about one week with a problem in Silverlight 4 + MVVM-Light toolkit and after searching the web without success I want to present my problem here and hope that somebody could give me some hints.

I want to present the simplified programm:

My model classes:

  1. Person

    public class Person
    {
    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

    public class 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; }
    }
    

    }

Here my 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);
        }
    }
}

In my view (PersonView) I have a combo box, a text box and a button:

<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>

When the button is clicked the first time everything works. The parameter (PersonInfo) passed after the button was clicked contains the selected ComboBox value (Cod_person) and the inserted text(Des_note). In the method SavePerson a new PersonInfo instance is assigned to the ChoosenPerson object. The problem occurs when I click the button a second time. Then as parameter after the button was clicked I get an instance of the PersonInfo class which contains the correct inserted text in the text box but as value selected in the combo box I always get 0, independet of what I choosed in the combo box. This problems occurs just in the case, that I use as combo box items instances of a class. If I use as combo box items just string values this problem does not occur. But I have to use instances of a class in my combo box.

I hope that somebody has a hint.
Thanks!

PS:

Interesting is still the fact, that when changing the assignment of the ChoosenPerson from "ChoosenPerson = new Model.PersonInfo();" to _choosenPerson = new Model.PersonInfo(); this means by assignment through use of private members instead of access methods, the second time the button is clicked, the values are written into the parameter of the button correctly. The only thing is that the values that were inserted the last time are not deleted. They are shown after the first button click. But they are not shown when the assignment of a new empty ChoosenPerson is made throuh access methods...
I can't explain this behavior. Who can help me?? Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

淡水深流 2024-10-07 10:37:14

亚当走在正确的道路上。我会将您的 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);
        }
    }
}

Adam was on the right track. I would assign your PersonViewModel to the DataContext instead of assigning it to the 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>

I would also totally get rid of the PersonInfo class. You do not need this class. You can work with the Person object directly. Change your references from PersonInfo to the Person class. Also, if you want to clear out the current selection in the ComboBox, set the ChoosenPerson property to null. Do not new up an instance of a class. The ChoosenPerson property needs to either be null or one of the objects in the AllPerson collection.

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);
        }
    }
}
愁以何悠 2024-10-07 10:37:14

我想你想要这样的东西:

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

I think you want something like this:

<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>

I updated most of the bindings. Once you set the UserControl's data context, the rest of the controls inside can simply reference the property name, instead of having to use the Locator. I also think you had a few things pointing to the wrong places.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文