Wpf Mvvm make an instance of NewCategory when createing a new Category

Anja 426 Reputation points
2021-04-11T08:39:58.723+00:00

Hi,
I have a window/usercontrol, where I want to make a new Category. So I have some controls (textbox, checkbox and so on), when writing in the first textcontrol, I want to make an instance of a NewCategory in the viewmodel, so when clicking on the save button I can save that instance NewCategory.

My problem is it doesn't make a instance of NewCategory.I go into the saveChangesNew but the NewCategory is still null.

What I'm doing wrong?

Best regards
Simsen :-)

<UserControl x:Class="Views.Account.AccountObsoleteViewCategoryNew"
             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:local="clr-namespace:Views.Account"
             xmlns:viewModel = "clr-namespace:ViewModel.Account;assembly=ViewModel"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid Grid.Row="0" Grid.Column="1">
        <Grid.RowDefinitions>
            <RowDefinition Height="465" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="489" />
        </Grid.ColumnDefinitions>
        <!--Række 0 meddelse-->
        <StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0" Width="480">
            <Label x:Name="LblMessageCategoryActive" Content="" BorderThickness="1" Height="50" />
        </StackPanel>
        <!--Række 1 med Ny knappe-->
        <Grid Grid.Row="2" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Right" Height="250">

            <Grid.RowDefinitions>
                <RowDefinition Height="5" />
                <RowDefinition Height="35" />
                <RowDefinition Height="35" />
                <RowDefinition Height="35" />
                <RowDefinition Height="35" />
                <RowDefinition Height="45" />
                <RowDefinition Height="55" />
                <RowDefinition Height="35" />
                <RowDefinition Height="200" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="5" />
                <ColumnDefinition Width="163" />
                <ColumnDefinition Width="183" />
            </Grid.ColumnDefinitions>
            <!--Row 1-->
            <Label x:Name="LblMessage" Content="" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" />

            <!--Row 2-->
            <Rectangle Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2"  Style="{StaticResource Row1}" />
            <Label Content="Navn:" Grid.Row="2" Grid.Column="1" HorizontalContentAlignment="Right" />
            <TextBox x:Name="TxtCategoryActiveNameNew" Margin="0 0 8 0" Text="{Binding Path=NewCategory, Mode=TwoWay, UpdateSourceTrigger=Explicit}" Grid.Row="2" Grid.Column="2" Height="25" />

            <!--Row 3-->
            <Rectangle Grid.Row="3" Grid.Column="1"  Style="{StaticResource Row2}" Grid.ColumnSpan="2" />
            <CheckBox x:Name="CbxCategoryActiveGlobalNew" Content="Global:" Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2" Margin="0 0 168 0" 
                      VerticalAlignment="Center"  HorizontalContentAlignment="Left" />

            <!--Row 4-->
            <Rectangle Grid.Row="4" Grid.Column="1"  Style="{StaticResource Row1}" Grid.ColumnSpan="2" />
            <CheckBox x:Name="CbxCategoryActiveActiveNew" Content="Inaktiv:" Grid.Row="4" Grid.Column="1" Margin="0 0 168 0" VerticalAlignment="Center"  
                                      HorizontalContentAlignment="Left" Grid.ColumnSpan="2" />

            <!--Row 5 -->
            <Rectangle Grid.Row="5" Grid.Column="1"  Style="{StaticResource Row2}" Grid.ColumnSpan="2" />
            <Label Content="Project:" Grid.Row="5" Grid.Column="1" HorizontalContentAlignment="Right" />
            <ComboBox x:Name="CbxProjectCategoryActiveNew" Grid.Row="5" Grid.Column="2" HorizontalContentAlignment="Left"  VerticalContentAlignment="Center"
                                      ItemsSource="{Binding Path=Projects_GetActive}" DisplayMemberPath="ProjectName" 
                                      SelectedValuePath="ProjectId" 
                                      Text="{Binding ElementName=LivCategories, Path=SelectedValue.ProjectName, Mode=TwoWay}"
                                      SelectedValue="{Binding Path=SelectedValue.ProjectId, Mode=TwoWay}">
            </ComboBox>
            <!--Row 6-->
            <Grid Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="3">
                <Grid.RowDefinitions>
                    <RowDefinition Height="10" />
                    <RowDefinition Height="35" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="200" />
                    <ColumnDefinition Width="10" />
                    <ColumnDefinition Width="200" />
                </Grid.ColumnDefinitions>
                <Button x:Name="BtnNewCancel" Content="Fortryd" Width="150" Grid.Column="0" Grid.Row="1" 
                    HorizontalAlignment="Center" HorizontalContentAlignment="Center" Click="BtnNewCancel_Click"  />
                <Button x:Name="BtnNewCategorySave" Content="Gem" Width="150" Grid.Column="2" Grid.Row="1" 
                    HorizontalAlignment="Left" HorizontalContentAlignment="Center" Click="BtnNewCategorySave_Click"
                      Command="{Binding CmdSaveNew}"  />
            </Grid>


        </Grid>
    </Grid>
</UserControl>

My ViewModel
using System.Collections.Generic;
using Model.Account;
using DAL.Account;
using System.Linq;
using Model.Projects;
using DAL.Projects;
using System.ComponentModel;
using System.Windows.Input;

namespace ViewModel.Account
{
    public class CategoryViewModel
    {
        public CategoryViewModel()
        {
            LoadCategories();
            LoadProjects();
            CmdReset = new MyICommand(ResetFields);
            CmdSave = new MyICommand(SaveChanges);
            CmdSaveNew = new MyICommand(SaveChangesNew);
        }

        #region New
        public MyICommand CmdReset { get; set; }
        private void ResetFields()
        {
            SelectedCategory.CategoryId = 0;
        }
        #endregion

        #region Get
        public List<Category> Categories_GetAll { get; set; }
        public List<Category> Categories_GetActive { get; set; }
        public List<Category> Categories_GetInactive { get; set; }

        public void LoadCategories()
        {
            DalCategory dalCategory = new DalCategory();
            var categories = dalCategory.GetCategories();

            if (categories != null)
            {
                //All
                Categories_GetAll = categories;

                //Active
                Categories_GetActive = categories.Where(x => x.CategoryIsObsolete == false).ToList();

                //Inactive
                Categories_GetInactive = categories.Where(x => x.CategoryIsObsolete == true).ToList();
            }
        }

        public List<Project> Projects_GetActive { get; set; }

        public void LoadProjects()
        {
            DalProjects dalProjects = new DalProjects();
            var projects = dalProjects.GetProjects();

            if (projects != null)
            {
                //Active
                Projects_GetActive = projects.Where(x => x.ProjectIsActive == true).ToList();
            }
        }
        #endregion

        #region Set
        public MyICommand CmdSave { get; set; }
        public void SaveChanges()
        {
            if (SelectedCategory != null)
            {
                if (SelectedCategory.CategoryId == 0)
                {
                    //Ny
                    string test = SelectedCategory.CategoryName;
                }
                else
                {
                    //Ret
                    string test = SelectedCategory.CategoryName;
                }
            }
            if (NewCategory != null)
            {
                string test = "ok";
            }
        }

        public MyICommand CmdSaveNew { get; set; }
        public void SaveChangesNew()
        {
            if (NewCategory != null)
            {
                string test = "ok";
            }
        }
        #endregion

        #region Delete
        public MyICommand DeleteCommand { get; set; }
        private void OnDelete()
        {
            Category cat = SelectedCategory;
            int id = cat.CategoryId;
            int pid = cat.ProjectId;
            string projectName = cat.ProjectName;
            int projectId = cat.ProjectId;
            string catname = cat.CategoryName;
            bool catGlobal = cat.CategoryIsGlobal;
            bool catActive = cat.CategoryIsObsolete;
            string test = "";
            //Categories_GetActive.Remove(SelectedCategory);
        }

        private bool CanDelete()
        {
            return SelectedCategory != null;
        }
        #endregion

        #region SelectedItem
        private Category _newCategory;
        public Category NewCategory
        {
            get
            {
                return _newCategory;
            }

            set
            {
                _newCategory = value;
                OnPropertyChanged("NewCategory");
            }
        }

        private Category _selectedCategory;

        public Category SelectedCategory
        {
            get
            {
                return _selectedCategory;
            }

            set
            {
                _selectedCategory = value;
                OnPropertyChanged("SelectedCategory");
            }
        }
        #endregion

        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }
}
Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,670 questions
0 comments No comments
{count} votes

Accepted answer
  1. Anja 426 Reputation points
    2021-04-11T13:16:42.2+00:00

    I give up. I make it instead reading each single value into the viewmodel

    <TextBox x:Name="TxtCategoryActiveNameNew" Margin="0 0 8 0"
                       Text="{Binding CategoryName}"  Grid.Row="2" Grid.Column="2" Height="25" />
    

    And get in the viewmodel with this

    public string CategoryName { get; set; }
    
    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Peter Fleischer (former MVP) 19,231 Reputation points
    2021-04-11T14:54:17.863+00:00

    Hi Anja,
    i would change the concept. In the ViewModel add a property CategoryView of the type Category and then bind the UI to this property. At the beginning a new instance is assigned and after each save a new instance is assigned again.

    Classes:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Windows;
    using System.Windows.Input;
    
    namespace WpfApp040
    {
      public class CategoryViewModel : INotifyPropertyChanged
      {
        public string Test { get; set; } = "VM test";
        public CategoryViewModel()
        {
          LoadCategories();
          LoadProjects();
          CmdReset = new MyICommand(ResetFields);
          CmdSave = new MyICommand(SaveChanges);
          CmdSaveNew = new MyICommand(SaveChangesNew);
        }
    
        #region New
        public MyICommand CmdReset { get; set; }
        private void ResetFields(object parameter) => CategoryView = new Category();
        #endregion
    
       #region new
        public MyICommand CmdSaveNew { get; set; }
        public void SaveChangesNew(object parameter)
        {
          // save new Category
          var x = CategoryView;
          ResetFields(null);
        }
        #endregion
    
        #region Get
        public List<Category> Categories_GetAll { get; set; }
        public List<Category> Categories_GetActive { get; set; }
        public List<Category> Categories_GetInactive { get; set; }
    
        public void LoadCategories()
        {
          DalCategory dalCategory = new DalCategory();
          var categories = dalCategory.GetCategories();
    
          if (categories != null)
          {
            //All
            Categories_GetAll = categories;
    
            //Active
            Categories_GetActive = categories.Where(x => x.CategoryIsObsolete == false).ToList();
    
            //Inactive
            Categories_GetInactive = categories.Where(x => x.CategoryIsObsolete == true).ToList();
          }
        }
    
        public List<Project> Projects_GetActive { get; set; }
    
        public void LoadProjects()
        {
          DalProjects dalProjects = new DalProjects();
          var projects = dalProjects.GetProjects();
    
          if (projects != null)
          {
            //Active
            Projects_GetActive = projects.Where(x => x.ProjectIsActive == true).ToList();
          }
        }
        #endregion
    
        #region Set
        public MyICommand CmdSave { get; set; }
        public void SaveChanges(object parameter)
        {
          if (SelectedCategory != null)
          {
            if (SelectedCategory.CategoryId == 0)
            {
              //Ny
              string test = SelectedCategory.CategoryName;
            }
            else
            {
              //Ret
              string test = SelectedCategory.CategoryName;
            }
          }
          //if (NewCategory != null)
          //{
          //  string test = "ok";
          //}
        }
        #endregion
    
        #region Delete
        public MyICommand DeleteCommand { get; set; }
        private void OnDelete()
        {
          Category cat = SelectedCategory;
          int id = cat.CategoryId;
          int pid = cat.ProjectId;
          string projectName = cat.ProjectName;
          int projectId = cat.ProjectId;
          string catname = cat.CategoryName;
          bool catGlobal = cat.CategoryIsGlobal;
          bool catActive = cat.CategoryIsObsolete;
          string test = "";
          //Categories_GetActive.Remove(SelectedCategory);
        }
    
        private bool CanDelete() => SelectedCategory != null;
        #endregion
    
        #region SelectedItem
        private Category _categoryView = new Category();
        public Category CategoryView
        {
          get => _categoryView;
          set
          {
            _categoryView = value;
            OnPropertyChanged(nameof(CategoryView));
          }
        }
    
        private Category _selectedCategory;
    
        public Category SelectedCategory
        {
          get => _selectedCategory;
          set
          {
            _selectedCategory = value;
            OnPropertyChanged("SelectedCategory");
          }
        }
        #endregion
    
        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propertyName) =>
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        #endregion
      }
    
      public class Category
      {
        public int CategoryId { get; set; }
        public int ProjectId { get; set; }
        public string ProjectName { get; set; }
        public string CategoryName { get; set; }
        public bool CategoryIsGlobal { get; set; }
        public bool CategoryIsObsolete { get; set; }
      }
    
      public class Project
      {
        public bool ProjectIsActive { get; set; }
      }
    
      internal class DalCategory
      {
        internal List<Category> GetCategories()
        {
          return new List<Category>();
        }
      }
    
      internal class DalProjects
      {
        internal List<Project> GetProjects()
        {
          return new List<Project>();
        }
      }
    
      public class MyICommand : ICommand
      {
        private readonly Predicate<object> _canExecute;
        private readonly Action<object> _action;
        public MyICommand(Action<object> action) { _action = action; _canExecute = null; }
        public MyICommand(Action<object> action, Predicate<object> canExecute) { _action = action; _canExecute = canExecute; }
        public void Execute(object o) => _action(o);
        public bool CanExecute(object o) => _canExecute == null ? true : _canExecute(o);
        public event EventHandler CanExecuteChanged
        {
          add { CommandManager.RequerySuggested += value; }
          remove { CommandManager.RequerySuggested -= value; }
        }
      }
    }
    

    XAML of UserControl:

    <UserControl x:Class="WpfControlLibrary1.Window040UC1"
                 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:local="clr-namespace:WpfControlLibrary1"
                 mc:Ignorable="d" 
                 d:DesignHeight="450" d:DesignWidth="800">
      <UserControl.Resources>
        <Style x:Key="Row1"/>
        <Style x:Key="Row2"/>
      </UserControl.Resources>
      <Grid Grid.Row="0" Grid.Column="1">
        <Grid.RowDefinitions>
          <RowDefinition Height="465" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="489" />
        </Grid.ColumnDefinitions>
        <!--Række 0 meddelse-->
        <StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0" Width="480">
          <Label x:Name="LblMessageCategoryActive" Content="" BorderThickness="1" Height="50" />
        </StackPanel>
        <Label Content="{Binding Test}"/>
        <!--Række 1 med Ny knappe-->
        <Grid Grid.Row="0"
              VerticalAlignment="Top" HorizontalAlignment="Right">
          <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
          </Grid.RowDefinitions>
          <Grid Grid.Row="0" DataContext="{Binding CategoryView}">
            <Grid.RowDefinitions>
              <RowDefinition Height="5" />
              <RowDefinition Height="35" />
              <RowDefinition Height="35" />
              <RowDefinition Height="35" />
              <RowDefinition Height="35" />
              <RowDefinition Height="45" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="5" />
              <ColumnDefinition Width="163" />
              <ColumnDefinition Width="183" />
            </Grid.ColumnDefinitions>
            <!--Row 1-->
            <Label x:Name="LblMessage" Content="" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" />
    
            <!--Row 2-->
            <Rectangle Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2"  Style="{StaticResource Row1}" />
            <Label Content="Navn:" Grid.Row="2" Grid.Column="1" HorizontalContentAlignment="Right" />
            <TextBox Grid.Row="2" Grid.Column="2" Height="25" Margin="0 0 8 0" 
                     Text="{Binding Path=CategoryName}"/>
    
            <!--Row 3-->
            <Rectangle Grid.Row="3" Grid.Column="1"  Style="{StaticResource Row2}" Grid.ColumnSpan="2" />
            <CheckBox Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2" Margin="0 0 168 0"  
                      VerticalAlignment="Center" HorizontalContentAlignment="Left" 
                      Content="Global:"
                      IsChecked="{Binding CategoryIsGlobal, Mode=TwoWay}"/>
    
            <!--Row 4-->
            <Rectangle Grid.Row="4" Grid.Column="1"  Style="{StaticResource Row1}" Grid.ColumnSpan="2" />
            <CheckBox Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2" Margin="0 0 168 0"  
                      VerticalAlignment="Center" HorizontalContentAlignment="Left"
                      Content="Inaktiv:"/>
    
            <!--Row 5 -->
            <Rectangle Grid.Row="5" Grid.Column="1"  Style="{StaticResource Row2}" Grid.ColumnSpan="2" />
            <Label Content="Project:" Grid.Row="5" Grid.Column="1" HorizontalContentAlignment="Right" />
            <ComboBox x:Name="CbxProjectCategoryActiveNew" Grid.Row="5" Grid.Column="2" 
                      HorizontalContentAlignment="Left"  VerticalContentAlignment="Center"
                      ItemsSource="{Binding Path=DataContext.Projects_GetActive, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" 
                      DisplayMemberPath="ProjectName" 
                      SelectedValuePath="ProjectId" 
                      Text="{Binding ElementName=LivCategories, Path=SelectedValue.ProjectName, Mode=TwoWay}"/>
          </Grid>
          <!--Row 6-->
          <Grid Grid.Row="1">
            <Grid.RowDefinitions>
              <RowDefinition Height="10" />
              <RowDefinition Height="35" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="200" />
              <ColumnDefinition Width="10" />
              <ColumnDefinition Width="200" />
            </Grid.ColumnDefinitions>
            <Button x:Name="BtnNewCancel" Grid.Column="0" Grid.Row="1" Width="150"
                    HorizontalAlignment="Center" HorizontalContentAlignment="Center"
                    Content="Fortryd"
                    Command="{Binding CmdReset}" />
            <Button x:Name="BtnNewCategorySave" Grid.Column="2" Grid.Row="1"
                    HorizontalAlignment="Left" HorizontalContentAlignment="Center"
                    Content="Gem" Width="150"
                    Command="{Binding CmdSaveNew}"  />
          </Grid>
        </Grid>
      </Grid>
    </UserControl>
    
    0 comments No comments