Q:

Why is it that unrelated properties are also being called multiple times in Winform databinding, and how to fix it?

This is my winform code:
partial class Form1
{
    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Windows Form Designer generated code

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        this.textBox1 = new System.Windows.Forms.TextBox();
        this.textBox2 = new System.Windows.Forms.TextBox();
        this.textBox3 = new System.Windows.Forms.TextBox();
        this.SuspendLayout();
        // 
        // textBox1
        // 
        this.textBox1.Location = new System.Drawing.Point(28, 129);
        this.textBox1.Name = "textBox1";
        this.textBox1.Size = new System.Drawing.Size(100, 20);
        this.textBox1.TabIndex = 0;
        this.textBox1.Leave += new System.EventHandler(this.textBox1_Leave);
        // 
        // textBox2
        // 
        this.textBox2.Location = new System.Drawing.Point(28, 227);
        this.textBox2.Name = "textBox2";
        this.textBox2.Size = new System.Drawing.Size(100, 20);
        this.textBox2.TabIndex = 1;
        // 
        // textBox3
        // 
        this.textBox3.Location = new System.Drawing.Point(28, 283);
        this.textBox3.Name = "textBox3";
        this.textBox3.Size = new System.Drawing.Size(100, 20);
        this.textBox3.TabIndex = 2;
        // 
        // Form1
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(579, 412);
        this.Controls.Add(this.textBox1);
        this.Controls.Add(this.textBox3);
        this.Controls.Add(this.textBox2);
        this.Name = "Form1";
        this.Text = "Form1";
        this.Load += new System.EventHandler(this.Form1_Load);
        this.ResumeLayout(false);
        this.PerformLayout();

    }

    #endregion

    private System.Windows.Forms.TextBox textBox1;
    private System.Windows.Forms.TextBox textBox2;
    private System.Windows.Forms.TextBox textBox3;
}

public partial class Form1 : Form
{

    private readonly Form1VM _vm;
    public Form1()
    {
        InitializeComponent();
        _vm = new Form1VM();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        BindControlsToVM();
    }

    private void BindControl(Control control, string propertyName)
    {
        control.DataBindings.Clear();
        control.DataBindings.Add(nameof(control.Text), _vm, propertyName);
    }
    private void BindControlsToVM()
    {
        BindControl(textBox1, nameof(_vm.Name));
        BindControl(textBox2, nameof(_vm.Surface));
        BindControl(textBox3, nameof(_vm.Surface1));
    }

    private void textBox1_Leave(object sender, EventArgs e)
    {

    }

    private void button1_Click(object sender, EventArgs e)
    {

    }
}

And this is my ViewModel ( I try to follow WPF in Winform)
public class Form1VM : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            OnPropertyChanged(nameof(Name));
            //OnPropertyChanged(nameof(Surface));
        }
    }

    private string _surface;
    public string Surface
    {
        get { return _surface; }
        set
        {
            _surface = value;
            OnPropertyChanged(nameof(Surface));
        }
    }

    private string _surface1;
    public string Surface1
    {
        get { return _surface1; }
        set
        {
            _surface1 = value;
            OnPropertyChanged(nameof(Surface1));
        }
    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

After the code compiles and runs, put the breakpoint at the get accessor at Name property. Now try to change either Surface or Surface1 properties at TextBox UI, you will find that Name property get accessor is also being invoked, multiple times even! 
There is a performance issue with this kind of calling. 
I've no idea why an unrelated property will get invoked when I change other properties, why is this so, and how to prevent it?

A:

I've no idea why an unrelated property will get invoked when I change other properties, why is this so...

For the class Form1VM, each property is unrelated to the others and you also implemented INotifyPropertyChanged to provide change notification, so you would expect that the binding mechanism to be smart enough to only pull values that have posted a change notification.  
Unfortunately, this is not the case and the default mechanism pulls all bound properties after it sends a change to the bound item.  The default mechanism does monitor INotifyPropertyChanged.PropertyChanged event responds pulling all bound values instead of just the changed one.
This is all handled by a PropertyManager that is maintained by the BindingContext Property of the control's ContainerControl.
The observed behavior appears to be the result of the PropertyManager.OnCurrentChanged Method that calls BindingManagerBase.PushData that ultimately results in an iteration over the bindings and calling Binding.PushData where the following code executes and retrieves the underlying data source value.
if (IsBinding) {
   dataSourceValue = bindToObject.GetValue();
   object controlValue = FormatObject(dataSourceValue);
   SetPropValue(controlValue);
   modified = false;
}

The subject code is declaring the binding such that the above sequence is triggered by the TextBox.Validating event.  When the underlying datasource (_vm) raises the PropertyChanged event, the sequence begins again with the PropertyManager.OnCurrentChanged method.

how to prevent it?

You could create a derived PropertyManager class that overrides OnCurrentChanged method and code your own behavior.  To get this custom class to be used, you would also need to create a custom BindingContext class to install it.  This is not something that I would recommend if you can accept a single polling of bound properties on changes propagated by the data binding mechanism.  This behavior can be accomplished by using a BindingSource as an intermediary between _vm and the binding.
The following shows the changes to the posted code necessary to use a BindingSource.
private BindingSource bs = new BindingSource();
public Form1()
{
    InitializeComponent();
    _vm = new Form1VM();
    bs.DataSource = _vm;
}

private void BindControl(Control control, string propertyName)
{
    control.DataBindings.Clear();
    control.DataBindings.Add(nameof(control.Text), bs, propertyName, true, DataSourceUpdateMode.OnValidation);
}

Another alternative is for Form1VM to implement the ICurrencyManagerProvider interface and provide a custom CurrencyManager Class implementation similar to the way the BindingSource class does.  This is something that I have never attempted, but I suspect it would be a similar task to deriving a custom PropertyManager.

