C# WPF应用程序MVVM-在Textbox上使用单向绑定,属性在再次获取数据后变为null
我有一个使用MVVM的WPF应用程序 我有一个绑定到ObservableCollection的DataGrid和一个绑定到DataGrid SelectedItem的文本框,因此当我单击DataGrid中的一个项目时,文本框被填充 我还有一个按钮,使用Command和CommandParameter,使用RelayCommand检查文本框是否为空,然后禁用按钮 如果我使用UpdateSourceTrigger=PropertyChanged,这一切都很好。我不喜欢的是因为绑定,如果用户更改文本框中的文本,就会编辑DataGrid记录。如果用户随后改变了更改记录的想法,并单击了其他地方,则DataGrid中的记录仍然显示编辑过的文本 我尝试在TextBox绑定上使用Mode=OneWay,其工作原理是它不会更新DataGrid记录。数据保存到数据库后,我需要手动刷新DataGrid以显示更改 我的代码隐藏中的代码是DataGrid的SelectionChanged事件,它将ViewModel上的属性设置为所选项 因此,为了显示新的更改,我认为在更改之后再次添加对GetCategories的调用会起作用。但是,当代码在PropertyChanged(“ReceivedCategories”)上执行时,我的CurrentCategory属性变为null 我的代码: CategoryModel.csC# WPF应用程序MVVM-在Textbox上使用单向绑定,属性在再次获取数据后变为null,c#,wpf,mvvm,C#,Wpf,Mvvm,我有一个使用MVVM的WPF应用程序 我有一个绑定到ObservableCollection的DataGrid和一个绑定到DataGrid SelectedItem的文本框,因此当我单击DataGrid中的一个项目时,文本框被填充 我还有一个按钮,使用Command和CommandParameter,使用RelayCommand检查文本框是否为空,然后禁用按钮 如果我使用UpdateSourceTrigger=PropertyChanged,这一切都很好。我不喜欢的是因为绑定,如果用户更改文本框
public class CategoryModel
{
public int CategoryID { get; set; }
public string Description { get; set; }
readonly SalesLinkerDataContext _dbContext = new SalesLinkerDataContext();
public ObservableCollection<CategoryModel> GetCategories()
{
var result = _dbContext.tblSalesCategories.ToList();
List<CategoryModel> categoriesList = result.Select(item => new CategoryModel
{
CategoryID = item.CategoryID,
Description = item.Description.Trim()
}).ToList();
return new ObservableCollection<CategoryModel>(categoriesList);
}
internal bool UpdateCategory(int id, string description)
{
if (_dbContext.tblSalesCategories.Any(x => x.Description == description))
{
MessageBox.Show("A category with the same name already exists.");
return false;
}
try
{
var category = (from a in _dbContext.tblSalesCategories
where a.CategoryID == id
select a).FirstOrDefault();
if (category != null)
{
category.Description = description;
_dbContext.SubmitChanges();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return false;
}
return true;
}
internal bool AddCategory(string description)
{
if (_dbContext.tblSalesCategories.Any(x => x.Description == description))
{
MessageBox.Show("A category with the same name already exists.");
return false;
}
var newCategory = new tblSalesCategory();
newCategory.Description = description;
try
{
_dbContext.tblSalesCategories.InsertOnSubmit(newCategory);
_dbContext.SubmitChanges();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return false;
}
return true;
}
internal bool DeleteCategory(int id)
{
var result = _dbContext.tblSalesCategories.FirstOrDefault(x => x.CategoryID == id);
try
{
if (result != null)
{
_dbContext.tblSalesCategories.DeleteOnSubmit(result);
_dbContext.SubmitChanges();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return false;
}
return true;
}
}
公共类类别模型
{
public int CategoryID{get;set;}
公共字符串说明{get;set;}
只读SalesLinkedDataContext _dbContext=new SalesLinkedDataContext();
公共可观测集合GetCategories()
{
var result=_dbContext.tblSalesCategories.ToList();
列表分类列表=结果。选择(项=>new CategoryModel
{
CategoryID=item.CategoryID,
Description=item.Description.Trim()
}).ToList();
返回新的ObservableCollection(分类列表);
}
内部bool UpdateCategory(int-id,字符串描述)
{
if(_dbContext.tblSalesCategories.Any(x=>x.Description==Description))
{
Show(“已经存在同名的类别”);
返回false;
}
尝试
{
var category=(来自_dbContext.tblSalesCategories中的
其中a.CategoryID==id
选择一个.FirstOrDefault();
如果(类别!=null)
{
类别.说明=说明;
_dbContext.SubmitChanges();
}
}
捕获(例外情况除外)
{
MessageBox.Show(例如Message);
返回false;
}
返回true;
}
内部bool AddCategory(字符串描述)
{
if(_dbContext.tblSalesCategories.Any(x=>x.Description==Description))
{
Show(“已经存在同名的类别”);
返回false;
}
var newCategory=新的tblSalesCategory();
newCategory.Description=描述;
尝试
{
_dbContext.tblSalesCategories.InsertOnSubmit(newCategory);
_dbContext.SubmitChanges();
}
捕获(例外情况除外)
{
MessageBox.Show(例如Message);
返回false;
}
返回true;
}
内部布尔删除类别(内部id)
{
var result=\u dbContext.tblSalesCategories.FirstOrDefault(x=>x.CategoryID==id);
尝试
{
如果(结果!=null)
{
_dbContext.tblSalesCategories.deleteoSubmit(结果);
_dbContext.SubmitChanges();
}
}
捕获(例外情况除外)
{
MessageBox.Show(例如Message);
返回false;
}
返回true;
}
}
CategoriesViewModel.cs
public class CategoriesViewModel : ViewModelBase, IPageViewModel
{
public CategoryModel CurrentCategory = new CategoryModel();
public ObservableCollection<CategoryModel> Categories = new ObservableCollection<CategoryModel>();
public RelayCommand GetCategoriesRelay;
public RelayCommand UpdateCategoryRelay;
public RelayCommand AddCategoryRelay;
public RelayCommand DeleteCategoryRelay;
#region Get Categories Command
public ICommand GetCategoriesCommand
{
get
{
GetCategoriesRelay = new RelayCommand(p => GetCategories(),
p => CanGetCategories());
return GetCategoriesRelay;
}
}
private bool CanGetCategories()
{
return true;
}
private void GetCategories()
{
Categories = CurrentCategory.GetCategories();
ReceivedCategories = Categories;
}
#endregion
#region Update Category Command
public ICommand UpdateCategoryCommand
{
get
{
UpdateCategoryRelay = new RelayCommand(p => UpdateCategory((string) p),
p => CanUpdateCategory());
return UpdateCategoryRelay;
}
}
public bool CanUpdateCategory()
{
return !String.IsNullOrWhiteSpace(Description);
}
public void UpdateCategory(string description)
{
if (CurrentCategory.UpdateCategory(CurrentCategory.CategoryID, description))
{
GetCategories();
}
}
#endregion
#region Add Category Command
public ICommand AddCategoryCommand
{
get
{
AddCategoryRelay = new RelayCommand(p => AddCategory((string) p),
p => CanAddCategory());
return AddCategoryRelay;
}
}
private bool CanAddCategory()
{
return !String.IsNullOrWhiteSpace(Description);
}
private void AddCategory(string description)
{
if (CurrentCategory.AddCategory(description))
GetCategories();
}
#endregion
#region Delete Category Command
public ICommand DeleteCategoryCommand
{
get
{
DeleteCategoryRelay = new RelayCommand(p => DeleteCategory((int) p),
p => CanDeleteCategory());
return DeleteCategoryRelay;
}
}
private bool CanDeleteCategory()
{
return true;
}
private void DeleteCategory(int id)
{
if (CurrentCategory.DeleteCategory(id))
GetCategories();
}
#endregion
/// <summary>
/// Describes the name that will be used for the menu option
/// </summary>
public string Name
{
get { return "Manage Categories"; }
}
public string Description
{
get
{
return CurrentCategory.Description;
}
set
{
CurrentCategory.Description = value;
OnPropertyChanged("Description");
}
}
public ObservableCollection<CategoryModel> ReceivedCategories
{
get { return Categories; }
set
{
Categories = value;
OnPropertyChanged("ReceivedCategories");
}
}
}
公共类分类ViewModel:ViewModelBase,IPageViewModel
{
public CategoryModel CurrentCategory=new CategoryModel();
公共ObservableCollection类别=新ObservableCollection();
公共关系命令GetCategoriesRelay;
公共中继命令更新类别中继;
公共继电器命令添加类别继电器;
公共关系命令DeleteCategoryRelay;
#区域获取类别命令
公共ICommand GetCategoriesCommand
{
得到
{
GetCategoriesRelay=new RelayCommand(p=>GetCategories(),
p=>CanGetCategories());
返回GetCategoriesRelay;
}
}
私人bool CanGetCategories()
{
返回true;
}
私有类别()
{
Categories=CurrentCategory.GetCategories();
接收类别=类别;
}
#端区
#区域更新类别命令
公共ICommand updateCategory命令
{
得到
{
UpdateCategoryRelay=new RelayCommand(p=>UpdateCategory((字符串)p),
p=>CanUpdateCategory());
返回UpdateCategoryRelay;
}
}
公共布尔CanUpdateCategory()
{
return!String.IsNullOrWhiteSpace(Description);
}
公共void UpdateCategory(字符串描述)
{
if(CurrentCategory.UpdateCategory(CurrentCategory.CategoryID,描述))
{
GetCategories();
}
}
#端区
#区域添加类别命令
公共ICommand AddCategoryCommand
{
得到
{
AddCategoryRelay=new RelayCommand(p=>AddCategory((字符串)p),
p=>CanAddCategory());
返回AddCategoryRelay;
}
}
私人bool CanAddCategory()
{
return!String.IsNullOrWhiteSpace(Description);
}
私有void AddCategory(字符串描述)
{
if(CurrentCategory.AddCategory(说明))
GetCategories();
}
#端区
#r
<UserControl x:Class="SalesLinker.CategoriesView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="600" Background="White">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding GetCategoriesCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="45"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Margin="20,0,0,0" FontSize="20" HorizontalAlignment="Center" Content="Categories"/>
<DataGrid x:Name="LstCategories" Grid.Column="0" Grid.Row="1" AutoGenerateColumns="false"
ItemsSource="{Binding Path=ReceivedCategories, Mode=TwoWay}" SelectionChanged="Selector_OnSelectionChanged"
HorizontalScrollBarVisibility="Disabled" GridLinesVisibility="None"
CanUserAddRows="False" CanUserDeleteRows="False" CanUserSortColumns="True" Background="White">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=Description}" IsReadOnly="True" Header="Description" Width="300" />
</DataGrid.Columns>
</DataGrid>
<Button Command="{Binding AddCategoryCommand}" Grid.Column="1" Grid.Row="1" VerticalAlignment="Top" Height="50" Width="50" Margin="0,20,0,0" Background="Transparent" BorderThickness="0" BorderBrush="Transparent"
CommandParameter="{Binding ElementName=TbDescription, Path=Text}">
<Image Source="/Images/Plus.png"/>
</Button>
<Button Command="{Binding DeleteCategoryCommand}" Grid.Column="1" Grid.Row="1" VerticalAlignment="Top" Height="50" Width="50" Margin="0,75,0,0" Background="Transparent" BorderThickness="0" BorderBrush="Transparent"
CommandParameter="{Binding SelectedItem.CategoryID, ElementName=LstCategories, Mode=OneWay }">
<Image Source="/Images/Minus.png"/>
</Button>
<Grid Grid.Row="1" Grid.Column="2">
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="0" Grid.Column="0" Content="Description:"/>
<TextBox x:Name="TbDescription" DataContext="CategoryModel" Grid.Row="0"
Grid.Column="1" Width="250" Height="Auto" VerticalAlignment="Center"
HorizontalAlignment="Left" Margin="10,0,0,0"
Text="{Binding SelectedItem.Description, ElementName=LstCategories, Mode=OneWay}"/>
<Button Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" Margin="10,0,0,0"
Height="20" Width="120" Content="Update Description"
Command="{Binding UpdateCategoryCommand}"
CommandParameter="{Binding ElementName=TbDescription, Path=Text}" />
</Grid>
</Grid>
//Your Copy List
ObservableCollection<CategoryModel> _ReceivedCategories;
//Your Execute command for the Gui
public void onUpdateExecuted(object parameter){
Dispatcher.Invoke(new Action(() => ReceivedCategories = new ObservableCollection <CategoryModel> (_ReceivedCategories));
}
//Your Undo Command if the Inputs are not ok
public void onUndoExecuted(object parameter){
Dispatcher.Invoke(new Action(() => _ReceivedCategories = new ObservableCollection <CategoryModel> (ReceivedCategories));
}
//Your Command on every input which is set
public void onInputExecuted(object parameter){
_ReceivedCategories.add(Your Object);
}
private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var viewmodel = (CategoriesViewModel)DataContext;
viewmodel.CurrentCategory = LstCategories.SelectedItems.Cast<CategoryModel>().FirstOrDefault();
}
private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var viewmodel = (CategoriesViewModel)DataContext;
if (LstCategories.SelectedIndex > -1)
viewmodel.CurrentCategory = LstCategories.SelectedItems.Cast<CategoryModel>().FirstOrDefault();
}