我之前尝试过提问,这是我在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
}