有条件地将两个属性绑定到一个文本框

Conditional binding two properties to one Textbox

你好亲爱的程序员

我决定使用 C# 语言学习 MVVP 模式。这就是为什么我有一个问题要问你。我有一个非常简单的应用程序,它由 5 个文本框和一个按钮组成。它还没有完成。

我取得的成绩:

  1. 当我在第一个文本框(员工姓名)中写一些文本时,动态 搜索启动,所有匹配的记录都出现在列表中。
  2. 当我单击列表中的记录时,信息会出现在文本框中。

我想达到的目标:

  1. 当我在第一个文本框(员工姓名)中写一些文本时,动态 搜索启动,所有匹配的记录都出现在列表中。
  2. 当我单击列表中的记录时,信息会出现在文本框中。
  3. 当我编辑列表中的第一个文本框(员工姓名)时,员工姓名 不应该改变。 (仅在单击按钮后)。

观察:

我阅读了有关多绑定、转换器和 UpdateSourcetrigger:Explicit 和 Propertychanged 的​​内容。我试图多重绑定文本框 TextboxEmployeeName。当我设置 PropertyChanged 时,动态搜索有效,但当我在文本框中写入时,列表中的员工姓名发生更改,但是当我设置显式时,列表中的员工姓名不会更改(我想要实现的),但动态搜索不起作用。

我的问题是:如何根据条件设置合适的UpdateSourceTrigger?

If (Record is not selected) 
{
UpdateSourceTrigger = PropertyChanged
}
Else If (Record is selected)
{
UpdateSourceTrigger = Explicit
}

不知道有没有好的办法解决我的问题。也许你知道更好的解决方案?你可以帮帮我吗?下面我放置了我的整个代码:

Employee.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Windows;
using System.Collections.ObjectModel;
using System.Windows.Data;
using System.Windows.Threading;

namespace OneWayTwoWayBinding
{
    public class Employee : INotifyPropertyChanged
    {
        private string employeeName;
        private string employeeID;
        private int? employeeSalary;
        private string employeeDesigner;
        private string employeeEmailID;
        private Employee selectedEmployee;
        private ICollectionView filteredCollection;
        private Employee dynamicSearch;
        private int changedPathBinding;
        public string EmployeeName
        {
            get
            {
                //Application.Current.Dispatcher.BeginInvoke(new Action(() => MessageBox.Show(employeeName)));
                return employeeName;
            }
            set
            {
                employeeName = value;
                if (FilteredCollection != null)
                    FilteredCollection.Filter = x => (String.IsNullOrEmpty(employeeName) || ((Employee)x).EmployeeName.Contains(employeeName));
                OnPropertyChanged("EmployeeName");
            }
        }
        public string EmployeeID
        {
            get
            {
                return employeeID;
            }
            set
            {
                employeeID = value;
                OnPropertyChanged("EmployeeID");
            }
        }
        public int? EmployeeSalary
        {
            get
            {
                return employeeSalary;
            }
            set
            {
                employeeSalary = value;
                OnPropertyChanged("EmployeeSalary");
                if (FilteredCollection != null)
                    FilteredCollection.Filter = x => ((employeeSalary == null) || ((Employee)x).EmployeeSalary == employeeSalary);
            }
        }
        public string EmployeeDesigner
        {
            get
            {
                //Application.Current.Dispatcher.BeginInvoke(new Action(() => MessageBox.Show(employeeDesigner)));
                return employeeDesigner;
            }
            set
            {
                employeeDesigner = value;
                OnPropertyChanged("EmployeeDesigner");
                if (FilteredCollection != null)
                FilteredCollection.Filter = x => (String.IsNullOrEmpty(employeeDesigner) || ((Employee)x).EmployeeDesigner.Contains(employeeDesigner));
            }
        }
        public string EmployeeEmailID
        {
            get
            {
                return employeeEmailID;
            }
            set
            {
                employeeEmailID = value;
                OnPropertyChanged("EmployeeEmailID");
            }
        }
        public IList<Employee> EmployeeList
        {
            get; set;
        }

        public Employee SelectedEmployee
        {
            get
            {
                //Application.Current.Dispatcher.BeginInvoke(new Action(() => MessageBox.Show(selectedEmployee.SelectedEmployee.ToString())));
                return selectedEmployee;
            }
            set
            {
                selectedEmployee = value;
                OnPropertyChanged("SelectedEmployee");
            }
        }

        public Employee DynamicSearch
        {
            get
            {
                return dynamicSearch;
            }
            set
            {
                dynamicSearch = value;
                OnPropertyChanged("DynamicSearch");
                //FilteredCollection.Filter = x => (String.IsNullOrEmpty(dynamicSearch.EmployeeName) || ((Employee)x).EmployeeName.Contains(dynamicSearch.EmployeeName));
            }
        }
        public ICollectionView FilteredCollection
        {
            get
            {
                return filteredCollection;
            }
            set
            {
                filteredCollection = value;
                OnPropertyChanged("FilteredCollection");
            }
        }

        public int ChangedPathBinding
        {
            get
            {
                //Application.Current.Dispatcher.BeginInvoke(new Action(() => MessageBox.Show(changedPathBinding.ToString())));
                return changedPathBinding;
            }
            set
            {
                changedPathBinding = value;
                OnPropertyChanged("ChangedPathBinding");
                //SelectedEmployee.EmployeeName
            }
        }

        public ObservableCollection<Employee> Employees { get; private set; }

        public event PropertyChangedEventHandler PropertyChanged = null;
        virtual protected void OnPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }
}

EmployeeViewModel.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;

namespace OneWayTwoWayBinding
{
    public class EmployeeViewModel : Employee
    {
        public EmployeeViewModel()
        {

            ObservableCollection<Employee> Employees = new ObservableCollection<Employee>()
            {
                new Employee{EmployeeName = "Adrian",EmployeeID = "1",EmployeeSalary = 15000,EmployeeDesigner = "SoftwareEngingeer12312", EmployeeEmailID = "drozd001@gmail423423.com"},
                new Employee{EmployeeName = "Bartek",EmployeeID = "2",EmployeeSalary = 15000,EmployeeDesigner = "SoftwareEngingeer",EmployeeEmailID = "drozd001@gmail.com"},
                new Employee{EmployeeName = "Czarek",EmployeeID = "3",EmployeeSalary = 30000,EmployeeDesigner = "SoftwareEngingeer",EmployeeEmailID = "drozd001@gmail.com"}
            };

            FilteredCollection = CollectionViewSource.GetDefaultView(Employees);

            //SelectedEmployee = new Employee {EmployeeName = string.Empty, EmployeeID = string.Empty, EmployeeSalary = string.Empty, EmployeeDesigner = string.Empty, EmployeeEmailID = string.Empty};

            //EmployeeDesigner = "SoftwareEngingeer12312";
            //EmployeeDesigner = "SoftwareEngingeer12312";
            //DynamicSearch.EmployeeName = "Czarek";
            //EmployeeSalary = 10;
            ChangedPathBinding = -1;
            SelectedEmployee = null;
        }

        RelayCommand _saveCommand;
        public ICommand SaveCommand
        {
            get
            {
                if (_saveCommand == null)
                {
                    _saveCommand = new RelayCommand((param) => this.Save(param),
                        param => this.CanSave);
                }
                return _saveCommand;
            }
        }

        public void Save(object parameter)
        {
            FilteredCollection.Filter = null;
            SelectedEmployee = null;
            EmployeeName = null;
            EmployeeSalary = null;
        }


        bool CanSave
        {
            get
            {
                return true;
            }
        }
    }

}

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace OneWayTwoWayBinding
{
    /// <summary>
    /// Logika interakcji dla klasy MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new EmployeeViewModel();
        }       
    }
}

Converters.cs

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;

namespace OneWayTwoWayBinding
{
    public class Converters : IValueConverter
    {
       public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
       {
            //value = 5; //ta liczba pojawi sie w textbox po uruchomieniu aplikacji
            return value;
       }
       public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
       {
        if (string.IsNullOrEmpty(value.ToString()))
            return null;
            //int var;
            //var = int.Parse(value.ToString());
            //var *= 2;
            //value = var;
        return value; //liczba wpisana w textbox z poziomu widoku aplikacji
       }
    }
    public class ConverterFiltering : IMultiValueConverter
    {
        public object Convert(object[] value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value[0] == DependencyProperty.UnsetValue || value[1] == DependencyProperty.UnsetValue)
            {
                return value[0];
            }
            MessageBox.Show("Values[0]: " + value[0].ToString());
            //MessageBox.Show("Values[1]: " + value[1].ToString());
            return value[0];
        }
        public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
        {
            string[] values = new string[2];
            values[0] = value.ToString();
            values[1] = value.ToString();

            MessageBox.Show("Values[0]: " + values[0].ToString() + " Values[1]: " + values[1].ToString());
            return values;
        }
    }
}

MainWindow.xaml

<Window x:Class="OneWayTwoWayBinding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:OneWayTwoWayBinding"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <local:Converters x:Key="NullableValueConverter" />
        <local:ConverterFiltering x:Key="ConverterFiltering" />
    </Window.Resources>
    <Grid Margin="0,0,0,20">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <ListView Name="EmployeeListView" HorizontalAlignment="Left" Height="160" Margin="0,259,0,0" VerticalAlignment="Top" Width="792" ItemsSource="{Binding FilteredCollection}" SelectedItem="{Binding SelectedEmployee, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedIndex="{Binding ChangedPathBinding}" >
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="EmployeeName" Width="150" DisplayMemberBinding="{Binding EmployeeName}" />
                    <GridViewColumn Header="EmployeeID" Width="150" DisplayMemberBinding="{Binding EmployeeID}" />
                    <GridViewColumn Header="EmployeeSalary" Width="150" DisplayMemberBinding="{Binding EmployeeSalary}" />
                    <GridViewColumn Header="EmployeeDesigner" Width="150" DisplayMemberBinding="{Binding EmployeeDesigner}" />
                    <GridViewColumn Header="EmployeeEmailID" Width="150" DisplayMemberBinding="{Binding EmployeeEmailID}" />
                </GridView>
            </ListView.View>
        </ListView>
        <Label Content="Employee Name" HorizontalAlignment="Left" Margin="15,52,0,0" VerticalAlignment="Top" Width="77" Height="23"/>

        <TextBox Name ="TextboxEmployeeName" HorizontalAlignment="Left" Height="23" Margin="97,52,0,0" VerticalAlignment="Top" Width="522" >
            <TextBox.Text>
                <MultiBinding Converter="{StaticResource ConverterFiltering}" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
                    <Binding Path="SelectedEmployee.EmployeeName" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" />
                    <Binding Path="EmployeeName"  Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"/>
                </MultiBinding>
            </TextBox.Text>
        </TextBox>

        <Label Content="Label" HorizontalAlignment="Left" Margin="15,91,0,0" VerticalAlignment="Top" Width="77" Height="23"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="97,91,0,0"  Text="{Binding Path=SelectedEmployee.EmployeeID, Mode=TwoWay}" VerticalAlignment="Top" Width="522"/>
        <Label Content="Label" HorizontalAlignment="Left" Margin="15,131,0,0" VerticalAlignment="Top" Width="77" Height="23"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="97,131,0,0"  Text="{Binding EmployeeSalary, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource NullableValueConverter}}" VerticalAlignment="Top" Width="522"/>
        <Label Content="Label" HorizontalAlignment="Left" Margin="15,176,0,0" VerticalAlignment="Top" Width="77" Height="23"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="97,176,0,0" Text="{Binding EmployeeDesigner, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="522"/>
        <Label Content="Label" HorizontalAlignment="Left" Margin="15,221,0,0" VerticalAlignment="Top" Width="77" Height="23"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="97,221,0,0"  Text="{Binding SelectedEmployee.EmployeeEmailID, Mode=TwoWay}" VerticalAlignment="Top" Width="522"/>
        <Button Content="Button" HorizontalAlignment="Left" Margin="663,116,0,0" VerticalAlignment="Top" Width="75" RenderTransformOrigin="-0.017,0.456" Command="{Binding SaveCommand}"/>
    </Grid>
</Window>

RelayCommand.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace OneWayTwoWayBinding
{
    public class RelayCommand : ICommand
    {
        #region Fields 
        readonly Action<object> _execute;
        readonly Predicate<object> _canExecute;
        #endregion // Fields 
        #region Constructors 
        public RelayCommand(Action<object> execute) : this(execute, null) { }
        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");
            _execute = execute; _canExecute = canExecute;
        }
        #endregion // Constructors 
        #region ICommand Members 
        [DebuggerStepThrough]
        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute(parameter);
        }
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
        public void Execute(object parameter) { _execute(parameter); }
        #endregion // ICommand Members 
    }
}

嗯,也许这个解决方案适合你?

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System.Collections.Generic;
using System.Linq;

namespace WpfApp1
{
    public class EmployeeModel
    {
        public string Name { get; set; }
    }


    public class EmployeeViewModel : ViewModelBase
    {
        readonly EmployeeModel model;
        string editName;

        public EmployeeViewModel (EmployeeModel model)
        {
            this.model = model;

            editName = Name;
            SaveChanges = new RelayCommand (() => { Name = EditName; SaveChanges.RaiseCanExecuteChanged (); }, () => IsDirty);
        }

        public string Name
        {
            get => model.Name;

            set
            {
                model.Name = value;
                RaisePropertyChanged (nameof (Name));
            }
        }

        public string EditName
        {
            get => editName;

            set
            {
                editName = value;
                RaisePropertyChanged (nameof (EditName));
                SaveChanges.RaiseCanExecuteChanged ();
            }
        }

        public bool IsDirty => editName != Name;

        public RelayCommand SaveChanges { get; }
    }


    public class WindowViewModel
    {
        List<EmployeeModel> models = new List<EmployeeModel>
        {
            new EmployeeModel () { Name = "Janusz" },
            new EmployeeModel () { Name = "Grażyna" },
            new EmployeeModel () { Name = "John" },
        };


        public WindowViewModel ()
        {
            EmployeeViews = models.Select (x => new EmployeeViewModel (x)).ToList ();
        }

        public IEnumerable<EmployeeViewModel> EmployeeViews { get; }

        public EmployeeViewModel SelectedEmployeeView { get; set; }
    }
}

和xaml:

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Window.DataContext>
        <local:WindowViewModel/>
    </Window.DataContext>

    <Grid>
        <ListBox ItemsSource="{Binding EmployeeViews}"
                 SelectedItem="{Binding SelectedEmployeeView}"
                 DisplayMemberPath="Name" Margin="26,26,565.6,0"

                 Height="274"
                 VerticalAlignment="Top"
                 Width="202"
                 />

        <Button Command="{Binding SelectedEmployeeView.SaveChanges}"
                Content="Save"
                HorizontalAlignment="Left"
                Height="36"
                Margin="245,81,0,0"
                VerticalAlignment="Top"
                Width="133"/>

        <TextBox Text="{Binding SelectedEmployeeView.EditName, UpdateSourceTrigger=PropertyChanged}"
                 HorizontalAlignment="Left"
                 Height="23"
                 Margin="255,35,0,0"
                 TextWrapping="Wrap" 
                 VerticalAlignment="Top"
                 Width="120"/>

    </Grid>
</Window>

我已经自己解决了我的问题。我已将我的全部代码放在下面 :)

Employee.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Windows;
using System.Collections.ObjectModel;
using System.Windows.Data;
using System.Windows.Threading;

namespace OneWayTwoWayBinding
{
    public class Employee : INotifyPropertyChanged
    {
        private string employeeName;
        private string employeeID;
        private int? employeeSalary;
        private string employeeDesigner;
        private string employeeEmailID;
        private Employee selectedEmployee;
        private ICollectionView filteredCollection;
        private string dynamicSearch;
        private int changedPathBinding;
        public string EmployeeName
        {
            get
            {
                return employeeName;
            }
            set
            {
                    employeeName = value;
                    if (FilteredCollection != null)
                        FilteredCollection.Filter = x => (String.IsNullOrEmpty(employeeName) || ((Employee)x).EmployeeName.Contains(employeeName));
                    OnPropertyChanged("EmployeeName");
            }
        }
        public string EmployeeID
        {
            get
            {
                return employeeID;
            }
            set
            {
                employeeID = value;
                OnPropertyChanged("EmployeeID");
            }
        }
        public int? EmployeeSalary
        {
            get
            {
                return employeeSalary;
            }
            set
            {
                employeeSalary = value;
                OnPropertyChanged("EmployeeSalary");
                if (FilteredCollection != null)
                    FilteredCollection.Filter = x => ((employeeSalary == null) || ((Employee)x).EmployeeSalary == employeeSalary);
            }
        }
        public string EmployeeDesigner
        {
            get
            {
                //Application.Current.Dispatcher.BeginInvoke(new Action(() => MessageBox.Show(employeeDesigner)));
                return employeeDesigner;
            }
            set
            {
                employeeDesigner = value;
                OnPropertyChanged("EmployeeDesigner");
                if (FilteredCollection != null)
                FilteredCollection.Filter = x => (String.IsNullOrEmpty(employeeDesigner) || ((Employee)x).EmployeeDesigner.Contains(employeeDesigner));
            }
        }
        public string EmployeeEmailID
        {
            get
            {
                return employeeEmailID;
            }
            set
            {
                employeeEmailID = value;
                OnPropertyChanged("EmployeeEmailID");
            }
        }
        public IList<Employee> EmployeeList
        {
            get; set;
        }

        public Employee SelectedEmployee
        {
            get
            {
                //Application.Current.Dispatcher.BeginInvoke(new Action(() => MessageBox.Show(selectedEmployee.SelectedEmployee.ToString())));
                return selectedEmployee;
            }
            set
            {
                selectedEmployee = value;
                OnPropertyChanged("SelectedEmployee");
            }
        }

        public string DynamicSearch
        {
            get
            {
                if (SelectedEmployee == null)
                {
                    EmployeeName = dynamicSearch;
                }
                return dynamicSearch;
            }
            set
            {
                    dynamicSearch = value;
                    OnPropertyChanged("DynamicSearch");
            }
        }
        public ICollectionView FilteredCollection
        {
            get
            {
                return filteredCollection;
            }
            set
            {
                filteredCollection = value;
                OnPropertyChanged("FilteredCollection");
            }
        }

        public int ChangedPathBinding
        {
            get
            {
                //Application.Current.Dispatcher.BeginInvoke(new Action(() => MessageBox.Show(changedPathBinding.ToString())));
                return changedPathBinding;
            }
            set
            {
                changedPathBinding = value;
                OnPropertyChanged("ChangedPathBinding");
                //SelectedEmployee.EmployeeName
            }
        }

        public ObservableCollection<Employee> Employees { get; private set; }

        public event PropertyChangedEventHandler PropertyChanged = null;
        virtual protected void OnPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }
}

EmployeeViewModel.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;

namespace OneWayTwoWayBinding
{
    public class EmployeeViewModel : Employee
    {
        public EmployeeViewModel()
        {

            ObservableCollection<Employee> Employees = new ObservableCollection<Employee>()
            {
                new Employee{EmployeeName = "Adrian",EmployeeID = "1",EmployeeSalary = 15000,EmployeeDesigner = "SoftwareEngingeer12312", EmployeeEmailID = "drozd001@gmail423423.com"},
                new Employee{EmployeeName = "Bartek",EmployeeID = "2",EmployeeSalary = 15000,EmployeeDesigner = "SoftwareEngingeer",EmployeeEmailID = "drozd001@gmail.com"},
                new Employee{EmployeeName = "Czarek",EmployeeID = "3",EmployeeSalary = 30000,EmployeeDesigner = "SoftwareEngingeer",EmployeeEmailID = "drozd001@gmail.com"}
            };

            FilteredCollection = CollectionViewSource.GetDefaultView(Employees);

            //SelectedEmployee = new Employee {EmployeeName = string.Empty, EmployeeID = string.Empty, EmployeeSalary = string.Empty, EmployeeDesigner = string.Empty, EmployeeEmailID = string.Empty};

            //EmployeeDesigner = "SoftwareEngingeer12312";
            //EmployeeDesigner = "SoftwareEngingeer12312";
            //DynamicSearch.EmployeeName = "Czarek";
            //EmployeeSalary = 10;
            ChangedPathBinding = -1;
            SelectedEmployee = null;
        }

        RelayCommand _saveCommand;
        public ICommand SaveCommand
        {
            get
            {
                if (_saveCommand == null)
                {
                    _saveCommand = new RelayCommand((param) => this.Save(param),
                        param => this.CanSave);
                }
                return _saveCommand;
            }
        }

        public void Save(object parameter)
        {
            string[] SearchedCollection = ((string)parameter).Split(new char[] { ':' });
            SelectedEmployee.EmployeeName = SearchedCollection[0];
            //FilteredCollection.Filter = null;
            SelectedEmployee = null;
            //EmployeeName = null;
            //EmployeeSalary = null;
        }


        bool CanSave
        {
            get
            {
                return SelectedEmployee != null;
            }
        }
    }

}

Converters.cs

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;

namespace OneWayTwoWayBinding
{
    public class Converters : IValueConverter
    {
       public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
       {
            //value = 5; //ta liczba pojawi sie w textbox po uruchomieniu aplikacji
            return value;
       }
       public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
       {
        if (string.IsNullOrEmpty(value.ToString()))
            return null;
            //int var;
            //var = int.Parse(value.ToString());
            //var *= 2;
            //value = var;
        return value; //liczba wpisana w textbox z poziomu widoku aplikacji
       }
    }
    public class ConverterFiltering : IMultiValueConverter
    {
        public object Convert(object[] value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value[0] == DependencyProperty.UnsetValue || value[1] == DependencyProperty.UnsetValue)
            {
                return value[0];
            }
            return value[0];
        }
        public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
        {
            string[] values = new string[2];
            values[0] = value.ToString();
            values[1] = value.ToString();
            return values;
        }
    }
    public class ConverterButton : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            string _employeeName = (string)values[0];
            //MessageBox.Show("ButtonConverter: " + _employeeName);
            return string.Format("{0}", _employeeName);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

MainWindows.xaml.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace OneWayTwoWayBinding
{
    /// <summary>
    /// Logika interakcji dla klasy MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new EmployeeViewModel();
        }       
    }
}

MainWindow.xaml

<Window x:Class="OneWayTwoWayBinding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:OneWayTwoWayBinding"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <local:Converters x:Key="NullableValueConverter" />
        <local:ConverterFiltering x:Key="ConverterFiltering" />
        <local:ConverterButton x:Key="ConverterButton" />
    </Window.Resources>
    <Grid Margin="0,0,0,20">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <ListView Name="EmployeeListView" HorizontalAlignment="Left" Height="160" Margin="0,259,0,0" VerticalAlignment="Top" Width="792" ItemsSource="{Binding FilteredCollection}" SelectedItem="{Binding SelectedEmployee, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedIndex="{Binding ChangedPathBinding}" >
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="EmployeeName" Width="150" DisplayMemberBinding="{Binding EmployeeName}" />
                    <GridViewColumn Header="EmployeeID" Width="150" DisplayMemberBinding="{Binding EmployeeID}" />
                    <GridViewColumn Header="EmployeeSalary" Width="150" DisplayMemberBinding="{Binding EmployeeSalary}" />
                    <GridViewColumn Header="EmployeeDesigner" Width="150" DisplayMemberBinding="{Binding EmployeeDesigner}" />
                    <GridViewColumn Header="EmployeeEmailID" Width="150" DisplayMemberBinding="{Binding EmployeeEmailID}" />
                </GridView>
            </ListView.View>
        </ListView>
        <Label Content="Employee Name" HorizontalAlignment="Left" Margin="15,52,0,0" VerticalAlignment="Top" Width="77" Height="23"/>

        <TextBox Name ="TextboxEmployeeName" HorizontalAlignment="Left" Height="23" Margin="97,52,0,0" VerticalAlignment="Top" Width="522" >
            <TextBox.Text>
                <MultiBinding Converter="{StaticResource ConverterFiltering}" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
                    <Binding Path="SelectedEmployee.EmployeeName" Mode="OneWay" UpdateSourceTrigger="PropertyChanged" />
                    <Binding Path="DynamicSearch"  Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"/>
                </MultiBinding>
            </TextBox.Text>
        </TextBox>

        <Label Content="Label" HorizontalAlignment="Left" Margin="15,91,0,0" VerticalAlignment="Top" Width="77" Height="23"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="97,91,0,0"  Text="{Binding Path=SelectedEmployee.EmployeeID, Mode=TwoWay}" VerticalAlignment="Top" Width="522"/>
        <Label Content="Label" HorizontalAlignment="Left" Margin="15,131,0,0" VerticalAlignment="Top" Width="77" Height="23"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="97,131,0,0"  Text="{Binding EmployeeSalary, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource NullableValueConverter}}" VerticalAlignment="Top" Width="522"/>
        <Label Content="Label" HorizontalAlignment="Left" Margin="15,176,0,0" VerticalAlignment="Top" Width="77" Height="23"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="97,176,0,0" Text="{Binding EmployeeDesigner, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="522"/>
        <Label Content="Label" HorizontalAlignment="Left" Margin="15,221,0,0" VerticalAlignment="Top" Width="77" Height="23"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="97,221,0,0"  Text="{Binding SelectedEmployee.EmployeeEmailID, Mode=TwoWay}" VerticalAlignment="Top" Width="522"/>
        <Button Content="Button" HorizontalAlignment="Left" Margin="663,116,0,0" VerticalAlignment="Top" Width="75" RenderTransformOrigin="-0.017,0.456" Command="{Binding SaveCommand}" >
            <Button.CommandParameter>
                <MultiBinding Converter="{StaticResource ConverterButton}" UpdateSourceTrigger="Explicit" Mode="TwoWay">
                    <Binding ElementName="TextboxEmployeeName" Path="Text"/>
                </MultiBinding>
            </Button.CommandParameter>
        </Button>
    </Grid>
</Window>

RelayCommand.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace OneWayTwoWayBinding
{
    public class RelayCommand : ICommand
    {
        #region Fields 
        readonly Action<object> _execute;
        readonly Predicate<object> _canExecute;
        #endregion // Fields 
        #region Constructors 
        public RelayCommand(Action<object> execute) : this(execute, null) { }
        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");
            _execute = execute; _canExecute = canExecute;
        }
        #endregion // Constructors 
        #region ICommand Members 
        [DebuggerStepThrough]
        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute(parameter);
        }
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
        public void Execute(object parameter) { _execute(parameter); }
        #endregion // ICommand Members 
    }
}