0
votes

How to store the content of TextBox in Model layer to be in line with MVVM?

I've made simple demo application to practice MVVM. It consists of main TextBox and 2 additional TextBoxes just for test if the app works properly.

In ViewModel I have TextContent class which implements INotifyPropertyChanged and it has Text property and the Text of MainTextBox is bindded to this and it works correctly.

In Model I have TextStore property which I try to update in the setter of Text property from ViewModel.TextContent, using simple method ModelUpdate().

And this model updating doesn't work.

Could you tell me ho can I transfer the content of TextBox which is stored in ViewModel property to the Model layer? And being in line in MVVM pattern?

Here the code:

View: (Here, the third TextBox is bindded to the model - I know, this is not compatible with MVVM idea but this is just for check the value of TextStore property from Model layer)

 <Window x:Class="MVVM_TBDB_2.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:MVVM_TBDB_2"
            xmlns:vm="clr-namespace:MVVM_TBDB_2.ViewModel"
            xmlns:m="clr-namespace:MVVM_TBDB_2.Model"
            Title="MainWindow" Height="350" Width="525">
        <Window.Resources>
            <m:TextContent x:Key="ModelTextContent" />
        </Window.Resources>
        <Window.DataContext>
            <vm:TextContent />
        </Window.DataContext>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="8*" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>

            <TextBox Name="MainTB" Grid.Row="0" Margin="10" AcceptsReturn="True" 
                    Text="{Binding Text, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"/>
            <Button Name="SaveButton" Content="Save" Grid.Row="1" Margin="10,2" Padding="20,0" HorizontalAlignment="Left"   />
            <TextBox Name="ControlTB" Grid.Row="1" Margin="30,2,2,2" Width="100" Text="{Binding Text, Mode=OneWay}" />
            <TextBox Name="ControlTB2" Grid.Row="1" Margin="300,2,2,2" Width="100" DataContext="{StaticResource ModelTextContent}"
                    Text="{Binding TextStock, Mode=TwoWay}" />
        </Grid>
    </Window>

ViewModel:

    class TextContent : INotifyPropertyChanged
        {
            private Model.TextContent model;

            public TextContent()
            {
                model = new Model.TextContent();
            }

            private string _Text;

            public string Text
            {
                get { return _Text; }
                set
                {

                    _Text = value;

                    OnPropertyChanged("Text");
                    ModelUpdate(_Text);

                }
            }

            private void OnPropertyChanged(string parameter)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(parameter));
            }

            public event PropertyChangedEventHandler PropertyChanged;

            private void ModelUpdate(string textToUpdate)
            {
                model.TextStock = textToUpdate;
            }
        }

Model:

  class TextContent
  {
      private string _TextStock;

      public string TextStock
      {
          get { return _TextStock; }
          set { _TextStock = value; }
      }

  }
1

1 Answers

0
votes

See Here I have implemented your requirement.

  1. Attach the data context from code behind.
  2. Implement the INotifyPropertyChanged interface in Model.
  3. Make the TextStock property as binded property.

MainWindow.cs

 public TextContent _model { get; set; }

    public TextContentViewModel _viewModel { get; set; }
    public MainWindow()
    {
        InitializeComponent();

        _viewModel = new TextContentViewModel();
        _model = new TextContent();

        this.DataContext = _viewModel;
        ControlTB2.DataContext = _model;
    }

Your ViewModel Class

private TextContent model;

    public TextContentViewModel()
    {

    }

    private string _Text;

    public string Text
    {
        get { return _Text; }
        set
        {

            _Text = value;

            OnPropertyChanged("Text");
            if (model != null)
            {
                ModelUpdate(_Text);
            }
            else
            {
                model = ((Application.Current.MainWindow as MainWindow).ControlTB2).DataContext as TextContent;
            }

        }
    }

    private void OnPropertyChanged(string parameter)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(parameter));
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void ModelUpdate(string textToUpdate)
    {
        model.TextStock = textToUpdate;
    }
}

Model Class

private string _TextStock;

    public string TextStock
    {
        get { return _TextStock; }
        set { _TextStock = value; OnPropertyChanged("TextStock"); }
    }

    private void OnPropertyChanged(string parameter)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(parameter));
    }

    public event PropertyChangedEventHandler PropertyChanged;

Note: I have renamed the class names as per my convenience.