2

I'm starting to learn wpf using mvvm by practicing a simple addition program. My application works fine.

But on running the application the textbox automatically assigning the default value 0.

I don't want the 0 before user provide any input.

view.xaml:

 <TextBox Height="28" Margin="112,56,46,0"  Text ="{Binding firstargument}"   Name="textBox1" VerticalAlignment="Top" />

ViewModel.cs

  private string _number1;
        public string firstargument
        {
            get { return _number1; }
            set
            {
                this._number1 = value;
                this.OnPropertyChanged("firstargument");

            }
        }

My question is to remove the value 0 in textbox after execution?

Edited:

ModelView.cs

 class ViewModel : INotifyPropertyChanged
    {


        public RelayCommand AddNew { get; set; }

        private int _number1;
        public int firstargument
        {
            get { return _number1; }
            set
            {


                this._number1 = value;
                this.OnPropertyChanged("firstargument");

            }
        }

        private int _number2;

        public int secondargument
        {
            get { return _number2; }
            set
            {
                this._number2 = value;

                this.OnPropertyChanged("secondargument");
            }
        }

        private int _number3;

        public int _addedargument
        {
            get { return _number3; }
            set
            {
                _number3 = value;
                this.OnPropertyChanged("_addedargument");
            }
        }
    public  ViewModel()
    {

        AddNew = new RelayCommand(o => AddNumbers());
    }


    private void AddNumbers()
    {
//Model instance is created here.
        Number p = new Number() { number1 = this._number1, number2 = this._number2 };

        var c = p.number1 + p.number2;
        _addedargument = c;

    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    #endregion

    }

view.Xaml

<Window x:Class="addition.Window1"
         xmlns:vm="clr-namespace:addition.ViewModel" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Window.DataContext>
        <vm:ViewModel />
    </Window.DataContext>
    <Grid>

        <Label Height="28" Margin="28,54,0,0" Name="Number1" VerticalAlignment="Top" HorizontalAlignment="Left" Width="48">Number</Label>
        <TextBox Height="28" Margin="112,56,46,0"  Text ="{Binding Path = firstargument}"   Name="textBox1" VerticalAlignment="Top" />
        <Label Margin="28,106,0,128" Name="Number2" Width="58" HorizontalAlignment="Left">Number1</Label>
        <TextBox Height="28" Margin="112,120,46,120" Text ="{Binding  Path = secondargument }" Name="textBox2" />
        <Label Height="28" Margin="28,0,0,75" Name="label1" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="58">Number2</Label>
        <TextBox Height="23" Margin="112,0,46,68" Name="textBox3" Text="{Binding _addedargument}" VerticalAlignment="Bottom" />
        <Button Height="23"  HorizontalAlignment="Left" Margin="39,0,0,16" Name="button1" VerticalAlignment="Bottom" Width="75" Command="{Binding AddNew}">Button</Button>
    </Grid>
</Window>

Edit : After implementing walteerlv solution the below addition logic is not working:

class ViewModel : INotifyPropertyChanged
    {
        int num;


        public RelayCommand AddNew { get; set; }

       private int? _number1;

public string FirstArgument
{

    get { return  _number1.ToString();}
    set
    {
        if (int.TryParse(_number1.ToString(), out num ))
        {
            this._number1 = num;
            OnPropertyChanged("FirstArgument");
        }
        else
        {
            _number1 = null;
        }
    }
}
        private int? _number2;

        public string secondargument
        {
            get { return _number2.ToString(); }

            set
            {
                if (int.TryParse(_number1.ToString(), out num))
                {
                    this._number2 = num;

                    this.OnPropertyChanged("secondargument");
                }
                else
                {
                    _number2 = null;
                }
            }
        }

        private int? _number3;

        public string _addedargument
        {
            get { return _number3.ToString(); }
            set
            {
                if (int.TryParse(_number1.ToString(), out num))
                {
                    this._number3 = num;

                    this.OnPropertyChanged("secondargument");
                }
                else
                {
                    _number3 = null;
                }
            }
        }



        public  ViewModel()
    {
        // The command receives an action on the constructor,
        // which is the action to execute when the command is invoked.


        AddNew = new RelayCommand(o => AddNumbers());



    }


    private void AddNumbers()
    {

        Number p = new Number() { number1 =this._number1.ToString(), number2 = this._number2.ToString() };

        MessageBox.Show(this._number1.ToString());
        int? c = Int32.Parse(p.number1) + Int32.Parse(p.number2);
        _addedargument = c.ToString();


    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    #endregion

    }

Let me know if you need further information.

Ramji R
  • 71
  • 1
  • 10
  • I've tried all your provided code and I get an empty TextBlock without any unexpected strings such as `0`. So you may have lost other important code that affects this behavior. – walterlv Dec 20 '18 at 04:47
  • @walterlv I have provided full code for viewmodel and view. Let me know whether you can replicate the behavior. – Ramji R Dec 20 '18 at 04:53
  • This question has so many edits it's hard to follow. The question needs to provide a single [mcve]. I suspect you simply need a Converter on your binding, and make the property a nullable int. Other tips: rather than use strings to contain the names of properties, prefer `nameof(YourProperty)`. And you can go a step further by using [CallerMemberName](https://stackoverflow.com/questions/22580623/is-callermembername-slow-compared-to-alternatives-when-implementing-inotifypro) so that most of the time you don't even need to do that. – Richardissimo Dec 20 '18 at 06:38

3 Answers3

1

Default value of int variables is 0. I think, this will help you

 private int? _number1;
    public int? firstargument
    {
        get { return _number1; }
        set
        {
            this._number1 = value;
            this.OnPropertyChanged("firstargument");
        }
    }
Dilshod K
  • 2,924
  • 1
  • 13
  • 46
1

I wrap the model's int property in a string property, because the TextBox.Text is a string and anything else will give conversion errors.

The ViewModel needs its own string rather than always converting the user's input into an int because the user might clear the box, or be part-way through typing '-1' and have a value that isn't a valid number. When you get a conversion error, the WPF binding can't update the view model, so you don't know there's a problem.

    private string firstArgument;

    public string FirstArgument
    {
        get
        {
            return this.firstArgument;
        }

        set
        {
            this.firstArgument= value;

            int tempInt;
            if (int.TryParse(value, out tempInt))
            {
                this.Model.FirstArgument = tempInt;
            }

            this.NotifyPropertyChanged();
        }
    }

The following is most of the code I use to validate that the string is a valid int.

    protected void NotifyPropertyChanged([CallerMemberName]string propertyName = null)
    {
        this.CheckForPropertyErrors();

        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }


    public override void CheckForPropertyErrors()
    {
        this.ValidateInt(this.FirstArgument , nameof(this.FirstArgument ));
    }


    protected void ValidateInt32(string value, string fieldName, string displayName = null)
    {
        int temp;
        if (!int.TryParse(value, out temp))
        {
            this.AddError(new ValidationError(fieldName, Constraints.NotInt32, $"{displayName ?? fieldName} must be an integer"));
        }
        else
        {
            this.RemoveError(fieldName, Constraints.NotInt32);
        }
    }
Robin Bennett
  • 3,192
  • 1
  • 8
  • 18
0

Reason

The reason why you get a 0 in your running window is that your binding properties are all int and 0 is the default value of an int.

0 of an int is a valid value for the XAML binding system, so you'll see that all the TextBoxes contains a 0 before you type anything.


Solution

All your properties should be a string and convert your actual numbers:

private int? _number1;

public string FirstArgument
{
    get => _number1?.ToString();
    set
    {
        if (int.TryParse(value, out var number))
        {
            _number1 = number;
            OnPropertyChanged("FirstArgument");
        }
        else
        {
            _number1 = null;
        }
    }
}

Notice:

  1. Because you may get a text that cannot be converted to int, so you can use int? to store a null value when you typed an error number.
  2. Convert your number to or from a string so that it can be displayed correctly into your XAML binding system.
  3. the property should be a string and cannot be an int? because the XAML binding system will not convert a string to an int automatically unless you convert it yourself or write a new IValueConverter.

Update

To implement the Add command, just use the fields instead of the properties.

private void AddNumbers()
{
    var a = _number1?.Value ?? 0;
    var b = _number2?.Value ?? 0;
    var c = a + b;
    _addedargument = c;
}

If you want to store the result into a model, then store the a, b, c values.

walterlv
  • 2,366
  • 13
  • 73
  • @walteerlv thanks for the comment i have changed the code and the issue has been resolved. but now my addition logic is not working after changing the code.I have updated my new code in question after changing. – Ramji R Dec 20 '18 at 06:05
  • Your add command need to change to use the `int?` instead of the string. – walterlv Dec 20 '18 at 06:55