C# WPF应用程序MVVM-在Textbox上使用单向绑定,属性在再次获取数据后变为null

C# WPF应用程序MVVM-在Textbox上使用单向绑定,属性在再次获取数据后变为null,c#,wpf,mvvm,C#,Wpf,Mvvm,我有一个使用MVVM的WPF应用程序 我有一个绑定到ObservableCollection的DataGrid和一个绑定到DataGrid SelectedItem的文本框,因此当我单击DataGrid中的一个项目时,文本框被填充 我还有一个按钮,使用Command和CommandParameter,使用RelayCommand检查文本框是否为空,然后禁用按钮 如果我使用UpdateSourceTrigger=PropertyChanged,这一切都很好。我不喜欢的是因为绑定,如果用户更改文本框

我有一个使用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.cs

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();
    }