ViewModel的新实例不会更新SelectedItem绑定

时间:2017-08-07 21:08:36

标签: c# wpf xaml mvvm

我之前尝试过提问,这是我在StackOverflow上的第一篇文章,所以它有点乱。我试着让这个更清楚一点。

所以我有一个InventoryView,它包含一个绑定到ObservableCollection的ComboBox,并且SelectedIngredient绑定到一个Ingredient对象。

程序正确地从数据库中读取并根据SelectedIngredient填充所有字段。但是,当我调用Save方法时,它似乎创建了View模型的新实例。这通常不是问题,因为除了SelectedIngredient之外所有属性都是正确的,它似乎是用null初始化的,并且在使用之前从不调用获取当前值。

我想知道是否有人对我的问题有任何解决方案。我对MVVM和数据绑定相当新,这个问题让我有点困难了一段时间。我假设我需要使用Save方法来使用ViewModel的相同实例,或者让新实例在创建时获取SelectedIngredient的值。我都不知道如何尝试解决这些问题。

如果需要更多信息,可以链接到完整的.cs和.xaml文件以及GitHub上的整个项目(我无法链接,因为我的链接不能超过2个哈哈。)

谢谢大家!

InventoryView.xaml(链接到完整档案)

<Window x:Class="MineralDatabase.App.Views.InventoryView"
    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:wpfToolkit="clr-namespace:Xceed.Wpf.Toolkit;assembly=Xceed.Wpf.Toolkit"
    xmlns:local="clr-namespace:MineralDatabase.App.Helpers"
    mc:Ignorable="d"
    Title="Inventory" Height="400" Width="440">
<Window.Resources>
    <local:IngredientTypeConverter x:Key="IngredientTypeConverter"/>
</Window.Resources>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <ToolBarTray Grid.Row="0">
        <ToolBar>
            <Button x:Name="btnNew" ToolTip="Add a new ingredient."  Click="btnNew_Click" >
                <StackPanel Orientation="Horizontal">
                    <Image Source="/icons/toolbar/new.png"/>
                    <TextBlock Margin="3,0,0,0"><Run Text="New"/></TextBlock>
                </StackPanel>
            </Button>
            <Button x:Name="btnRename" ToolTip="Rename current ingredient." Click="btnRename_Click" >
                <StackPanel Orientation="Horizontal">
                    <Image Source="/icons/toolbar/rename.png"/>
                    <TextBlock Margin="3,0,0,0"><Run Text="Rename"/></TextBlock>
                </StackPanel>
            </Button>
            <Button x:Name="btnDelete" ToolTip="Deletes current Ingredient." >
                <StackPanel Orientation="Horizontal">
                    <Image Source="/icons/toolbar/delete.png"/>
                    <TextBlock Margin="3,0,0,0"><Run Text="Delete"/></TextBlock>
                </StackPanel>
            </Button>
            <Separator />
            <Button x:Name="btnManufacturers" ToolTip="Displays manufacturer info." Click="btnManufacturers_Click" >
                <StackPanel Orientation="Horizontal">
                    <Image Source="/icons/toolbar/manufacturers.png"/>
                    <TextBlock Margin="3,0,0,0"><Run Text="Manufacturers"/></TextBlock>
                </StackPanel>
            </Button>
            <Separator />
            <Button x:Name="SaveAllChanges" ToolTip="Save all changes." Click="btnSave_Click" VerticalAlignment="Top" >
                <StackPanel Orientation="Horizontal">
                    <Image Source="/icons/toolbar/save.png"/>
                    <TextBlock Margin="3,0,0,0"><Run Text="Save"/></TextBlock>
                </StackPanel>
            </Button>
            <Button x:Name="btnExit" ToolTip="Exit ingredients manager." Click="btnExit_Click" >
                <StackPanel Orientation="Horizontal">
                    <Image Source="/icons/toolbar/exit.png"/>
                    <TextBlock Margin="3,0,0,0"><Run Text="Exit"/></TextBlock>
                </StackPanel>
            </Button>
        </ToolBar>
    </ToolBarTray>
    <Border Grid.Row="1" Margin="10">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height ="Auto" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <StackPanel Orientation="Vertical" Grid.Row="0">
                <StackPanel Orientation="Vertical">
                    <TextBlock Text="Ingredient Name" />
                    <ComboBox x:Name="ComboBoxIngredientName" Margin="0,0,0,3" 
                              ItemsSource="{Binding IngredientList}" 
                              DisplayMemberPath="Name" 
                              SelectedValuePath="Id"
                              SelectedItem="{Binding SelectedIngredient, Mode=TwoWay}"
                              IsSynchronizedWithCurrentItem="True"/>
                    <TextBlock Text="Manufacturer"/>
                    <ComboBox Margin="0,0,0,3"
                              ItemsSource="{Binding SupplierNameList}"
                              SelectedItem="{Binding SelectedIngredient.Manufacturer}"/>
                </StackPanel>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="3*" />
                    </Grid.ColumnDefinitions>
                    <StackPanel Grid.Column="0">
                        <TextBlock Text="Type" Margin="0,0,0,3"/>
                        <CheckBox Content="Base" Margin="0,0,0,3" 
                                  IsChecked="{Binding SelectedIngredient.Type, Converter={StaticResource IngredientTypeConverter},ConverterParameter=0}"/>
                        <CheckBox Content="Oxide" Margin="0,0,0,3" 
                                  IsChecked="{Binding SelectedIngredient.Type, Converter={StaticResource IngredientTypeConverter},ConverterParameter=1}"/>
                        <CheckBox Content="Additive" Margin="0,0,0,3" 
                                  IsChecked="{Binding SelectedIngredient.Type, Converter={StaticResource IngredientTypeConverter},ConverterParameter=2}"/>
                        <CheckBox Content="Other" Margin="0,0,0,3" 
                                  IsChecked="{Binding SelectedIngredient.Type, Converter={StaticResource IngredientTypeConverter},ConverterParameter=3}"/>
                    </StackPanel>
                    <GroupBox Grid.Column="1" Header="Cost">
                        <Border Margin="5">
                            <StackPanel Orientation="Vertical">
                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                    <TextBlock Text="Cost" VerticalAlignment="Center" Margin="0,0,5,0" />
                                    <wpfToolkit:DecimalUpDown Width="75" Value="0.00" Margin="0,0,0,5"/>
                                    <TextBlock Text="Volume" VerticalAlignment="Center" Margin="5,0,5,0"/>
                                    <wpfToolkit:DecimalUpDown Width="75" Value="0.00" Margin="0,0,0,5"/>
                                </StackPanel>
                                <Button Content="Add to Inventory" Width="100"/>
                            </StackPanel>
                        </Border>
                    </GroupBox>
                </Grid>
                <StackPanel Orientation="Vertical">
                    <StackPanel Orientation="Horizontal" Margin="0,5,0,0">
                        <TextBlock Text="Inventory amount" VerticalAlignment="Center" Margin="0,0,5,0"/>
                        <wpfToolkit:DecimalUpDown Width="80"  Value="{Binding SelectedIngredient.InventoryAmount}" />
                        <TextBlock Text="Inventory alarm" VerticalAlignment="Center" Margin="5,0,5,0"/>
                        <wpfToolkit:DecimalUpDown Width="80"  Value="{Binding SelectedIngredient.InventoryThreshold}"/>
                    </StackPanel>
                    <DockPanel>
                        <TextBlock Text="Storage location" VerticalAlignment="Center" Margin="0,5,12,0" />
                        <TextBox Text="{Binding SelectedIngredient.Location}" Margin="0,5,0,0"/>
                    </DockPanel>
                </StackPanel>
            </StackPanel>
            <DockPanel Grid.Row="2">
                <TextBlock Text="Notes" Margin="0,3,5,0" />
                <wpfToolkit:RichTextBox Text="{Binding SelectedIngredient.Notes}" Margin="0,3,0,0">
                    <wpfToolkit:RichTextBox.TextFormatter>
                        <wpfToolkit:RtfFormatter />
                    </wpfToolkit:RichTextBox.TextFormatter>
                </wpfToolkit:RichTextBox>
            </DockPanel>
        </Grid>
    </Border>
</Grid>

InventoryViewModel.cs(链接到完整档案)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Caliburn.Micro;
using MineralDatabase.App.Models;
using System.Collections.ObjectModel;
using System.Data.Entity;

namespace MineralDatabase.App.ViewModels
{
    public partial class InventoryViewModel : PropertyChangedBase
    {
        #region Constructor
        public InventoryViewModel()
        {
            GetAllIngredients();
            GetAllSuppliers();
            GetSuppliersNames();
        }
        #endregion

        #region Properties
        MineralDBEntities db = new MineralDBEntities();

        private ObservableCollection<Manufacturer> _supplierList;
        public ObservableCollection<Manufacturer> SupplierList
        {
            get { return _supplierList; }
            set
            {
                _supplierList = value;
                NotifyOfPropertyChange(() => SupplierList);
            }
        }

        private Manufacturer _selectedSupplier;
        public Manufacturer SelectedSupplier
        {
            get { return _selectedSupplier; }
            set
            {
                _selectedSupplier = value;
                NotifyOfPropertyChange(() => SelectedSupplier);
            }
        }

        private ObservableCollection<Ingredient> _ingredientList;
        public ObservableCollection<Ingredient> IngredientList
        {
            get { return _ingredientList; }
            set
            {
                _ingredientList = value;
                NotifyOfPropertyChange(() => IngredientList);
            }
        }

        private Ingredient _selectedIngredient;
        public Ingredient SelectedIngredient
        { 
            get
            {
                return _selectedIngredient;
            }
            set
            {
                if (_selectedIngredient != value)
                {
                    _selectedIngredient = value;
                    NotifyOfPropertyChange(() => SelectedIngredient);
                }
            }
        }

        private List<string> _supplierNameList;
        public List<string> SupplierNameList
        {
            get { return _supplierNameList; }
            set
            {
                _supplierNameList = value;
                NotifyOfPropertyChange(() => SupplierNameList);
            }
        }

        #endregion

        #region Methods
        public void GetAllIngredients()
        {
            db.Ingredients.Load();
            IngredientList = db.Ingredients.Local;
        }

        public void GetAllSuppliers()
        {
            db.Manufacturers.Load();
            SupplierList = db.Manufacturers.Local;
        }

        public void GetSuppliersNames()
        {
            db.Manufacturers.Load();
            var result = db.Manufacturers.Select(x => x.CompanyName).ToList();
            SupplierNameList = result;
        }

        public void SaveAllChanges()
        {
            var result = db.Ingredients.SingleOrDefault(b => b.Name == SelectedIngredient.Name);
            if (result != null)
            {
                result = SelectedIngredient;
                db.SaveChanges();
            }
            else
            {
                Ingredient i = new Ingredient();
                i = SelectedIngredient;

                if (i.Name != null || i.Name != String.Empty)
                {
                    db.Ingredients.Add(i);
                    try
                    {
                        db.SaveChanges();
                    }
                    catch (System.Data.Entity.Validation.DbEntityValidationException dbEx)
                    {
                        Exception raise = dbEx;
                        foreach (var validationErrors in dbEx.EntityValidationErrors)
                        {
                            foreach (var validationError in validationErrors.ValidationErrors)
                            {
                                string message = string.Format("{0}:{1}",
                                    validationErrors.Entry.Entity.ToString(),
                                    validationError.ErrorMessage);
                                // raise a new exception nesting
                                // the current instance as InnerException
                                raise = new InvalidOperationException(message, raise);
                            }
                        }
                        throw raise;
                    }
                }
            }
        }
    }
    #endregion
}

0 个答案:

没有答案