WPF Converter is not working - c#

Friends I am using converter for the first time. I want to convert between Bool and String for the Visibility purpose of Button 'Help'. Getter-Setter for HelpVisibility are working but I am not sure why visibility of button is not working. Below is my code. Please help.
VehicalForm.xaml
<Window x:Class="Seris.VehicleForm"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="500" Width="650"
xmlns:l="clr-namespace:Seris.Converters">
<Window.Resources>
<l:Bool2String x:Key="converter" />
</Window.Resources>
<Control>
<Control.Template>
<ControlTemplate>
<WrapPanel Orientation="Vertical" Margin="10 " >
<Label Content="Vehical No" HorizontalAlignment="Left"/>
<TextBox Name="VehicalNo_Text" Height="23" Width="80" TextWrapping="Wrap" Text="{Binding VehicalNo, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" />
<Label Content="Model" HorizontalAlignment="Left"/>
<TextBox Name="Model_Text" Height="23" Width="80" TextWrapping="Wrap" Text="{Binding Model, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" />
<Label Content="Manufacturing Date" HorizontalAlignment="Left"/>
<DatePicker Name="ManufacturingDate_DateTime" SelectedDate="{Binding ManufacturingDate, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Width="136"/>
<Label Content="IU No" HorizontalAlignment="Left"/>
<TextBox Height="23" Width="80" Name="IUNO_Text" TextWrapping="Wrap" Text="{Binding IUNo, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left"/>
<Label Content="Personnel" HorizontalAlignment="Left"/>
<ComboBox Name="Personnel_Combo" SelectedValue="{Binding PersonnelNameSelected, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding PersonnelName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" HorizontalAlignment="Left" Width="126"/>
<Separator Height="20" RenderTransformOrigin="0.5,0.5" Width="16"/>
<Button Name="Save_Button" Command="{Binding SaveButton_Command}" Content="Save" Width="66"/>
<Button Name="Replace_Button" CommandParameter="replace" IsEnabled="{Binding isEnableReplaceButton, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Command="{Binding ReplaceButton_Command}" Content="Replace" Width="66"/>
<Button Name="Remove_Button" CommandParameter="replace" IsEnabled="{Binding isEnableReplaceButton, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Command="{Binding RemoveButton_Command}" Content="Remove" Width="66"/>
<Label x:Name="Error_Label" Content="{Binding ErrorMessage, UpdateSourceTrigger=PropertyChanged}" Foreground="Red" HorizontalAlignment="Left" Height="41" Width="137"/>
<ListView Name ="Grid" Height="294" Width="371" >
<DataGrid Name="DG" ItemsSource="{Binding ListItems, UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding SelectedRow, Mode=TwoWay}" GridLinesVisibility="None" IsReadOnly="True" AutoGenerateColumns="False" BorderThickness="0">
<DataGrid.Columns>
<DataGridTextColumn Header="Vehical No" Binding="{Binding VehicalNo}"/>
<DataGridTextColumn Header="Model" Binding="{Binding Model}" />
<DataGridTextColumn Header="ManufacturingDate" Binding="{Binding ManufacturingDate}" />
<DataGridTextColumn Header="IUNo" Binding="{Binding IUNo}" />
<DataGridTextColumn Header="Personnel" Binding="{Binding PersonnelNameSelected}" />
</DataGrid.Columns>
</DataGrid>
</ListView>
<TextBlock Name="Notification" Text="{Binding EditText, UpdateSourceTrigger=PropertyChanged}"/>
<ProgressBar Name="Progressbar" Minimum="0" Maximum="100" Value="{Binding Progress, UpdateSourceTrigger=PropertyChanged}" Height="11"/>
<TextBlock Text="{Binding ElementName=Progressbar, Path=Value, StringFormat={}{0:0}%}" HorizontalAlignment="Center" VerticalAlignment="Center" />
<Button Name="Help" Visibility="{Binding HelpVisibility, Converter={StaticResource converter}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" CommandParameter="help" Height="50" Width="50" Click="Help_Click" HorizontalAlignment="Right">
<Image Height="45" Width="45" Source="../Images/help.jpg" HorizontalAlignment="Left"/>
</Button>
</WrapPanel>
</ControlTemplate>
</Control.Template>
</Control>
</Window>
Bool2String.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
namespace Seris.Converters
{
class Bool2String : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is bool)
return bool.TrueString;
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is string)
{
if (value == "true")
return true;
else if (value == "false")
return false;
}
return null;
}
}
}
VehicalMainViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Seris.Models;
using System.Collections.ObjectModel;
using System.Windows.Input;
using Seris.Commands;
using Seris.ViewModels;
using System.Windows;
using System.Windows.Controls;
using System.Threading;
using System.ComponentModel;
using Seris.Views;
namespace Seris.ViewModels
{
public class VehicleMainViewModel : ObservableObject
{
#region Getters-Setters
// Static Variables
private static bool _IsEnableReplaceButton;
public static bool IsEnableReplaceButton
{
get { return _IsEnableReplaceButton; }
set { _IsEnableReplaceButton = value; }
}
// Non-Static Variables
public ObservableCollection<VehicleModel> _listItems;
public ObservableCollection<VehicleModel> ListItems
{
get { return _listItems; }
set
{
if (value == null || (!value.Equals(_listItems)))
{
_listItems = value;
}
}
}
private int _Progress;
public int Progress
{
get { return _Progress; }
set { _Progress = value; OnPropertyChanged("Progress"); }
}
private string _ErroMesage;
public string ErrorMessage
{
get { return _ErroMesage; }
set
{
_ErroMesage = value; OnPropertyChanged("ErrorMessage");
if (ErrorMessage.Trim() == "" || ErrorMessage == null)
HelpVisibility = false;
else
HelpVisibility = true;
}
}
private bool _HelpVisibility;
public bool HelpVisibility
{
get { return _HelpVisibility; }
set { _HelpVisibility = value; OnPropertyChanged("HelpVisibility"); }
}
private Guid? _UniqueNo;
public Guid? UniqueNo
{
get { return _UniqueNo; }
set
{
if (value == null || (!value.Equals(_UniqueNo)))
{
_UniqueNo = value;
OnPropertyChanged("VehicalNo");
}
}
}
private string _VehicalNo;
public string VehicalNo
{
get { return _VehicalNo; }
set
{
if (value == null || (!value.Equals(_VehicalNo)))
{
_VehicalNo = value;
EditText = _VehicalNo;
OnPropertyChanged("VehicalNo");
}
}
}
private string _Model;
public string Model
{
get { return _Model; }
set
{
if (value == null || (!value.Equals(_Model)))
{
_Model = value;
EditText = _Model;
OnPropertyChanged("Model");
}
}
}
private DateTime? _ManufacturingDate;
public DateTime? ManufacturingDate
{
get { return _ManufacturingDate; }
set
{
if (value == null || (!value.Equals(_ManufacturingDate)))
{
_ManufacturingDate = value;
EditText = _ManufacturingDate.ToString();
OnPropertyChanged("ManufacturingDate");
}
}
}
private string _IUNo;
public string IUNo
{
get { return _IUNo; }
set
{
if (value == null || (!value.Equals(_IUNo)))
{
_IUNo = value;
EditText = _IUNo;
OnPropertyChanged("IUNo");
}
}
}
private ObservableCollection<string> _PersonnelName;
public ObservableCollection<string> PersonnelName
{
get { return _PersonnelName; }
set
{
if (value != _PersonnelName)
{
_PersonnelName = value;
EditText = _VehicalNo;
OnPropertyChanged("PersonnelName");
}
}
}
private string _PersonnelNameSelected;
public string PersonnelNameSelected
{
get { return _PersonnelNameSelected; }
set
{
if (value != _PersonnelNameSelected)
{
_PersonnelNameSelected = value;
EditText = _PersonnelNameSelected;
OnPropertyChanged("PersonnelNameSelected");
}
}
}
private string _EditText;
public string EditText
{
get { return _EditText; }
set
{
if (value != _EditText)
{
_EditText = value;
OnPropertyChanged("EditText");
}
}
}
private VehicleModel _SelectedRow;
public VehicleModel SelectedRow
{
get { return _SelectedRow; }
set
{
if (value != _SelectedRow)
{
_SelectedRow = value;
OnPropertyChanged("SelectedRow");
if (SelectedRow != null)
{
UniqueNo = _SelectedRow.UniqueNo;
VehicalNo = _SelectedRow.VehicalNo;
Model = _SelectedRow.Model;
ManufacturingDate = _SelectedRow.ManufacturingDate;
IUNo = _SelectedRow.IUNo;
PersonnelNameSelected = _SelectedRow.PersonnelNameSelected;
_IsEnableReplaceButton = true;
}
}
}
}
#endregion
#region Command Objects
private ICommand _saveButton_Command;
public ICommand SaveButton_Command
{
get { return _saveButton_Command; }
set { _saveButton_Command = value; }
}
private ICommand _ReplaceButton_Command;
public ICommand ReplaceButton_Command
{
get { return _ReplaceButton_Command; }
set { _ReplaceButton_Command = value; }
}
private ICommand _RemoveButton_Command;
public ICommand RemoveButton_Command
{
get { return _RemoveButton_Command; }
set { _RemoveButton_Command = value; }
}
#endregion
#region Methods
//Static Methods
#region Constructors
public VehicleMainViewModel()
{
// Initialization
VehicleModel vm = new VehicleModel();
ListItems = new ObservableCollection<VehicleModel>();
PersonnelName = ListOfPersonnelViewModel.PersonNameList_Updating;
//PersonnelName = new ObservableCollection<string>() { "ABC", "DEF", "GHI" };
// Setting Flags
ErrorMessage = "";
IsEnableReplaceButton = false;
//
// Commands Initialization
SaveButton_Command = new RelayCommand(new Action<object>(SaveToList));
ReplaceButton_Command = new RelayCommand(new Action<object>(ReplaceToList));
RemoveButton_Command = new RelayCommand(new Action<object>(RemoveList));
}
#endregion
}
}

In your converter you should return Visibilty.Visible or Visibility.Collapsed, not true or false or string .

Visibility property accepts value as "Hidden", "Collapse" or "Visible". You need to set these values to Visibility property.
You can refer following link for code to BoolToVisibilityconverter
WPF Converter Property
Please dont forget to like answer if you find it useful.

Related

.NET MAUI - DatePicker Selection in Does Not Update Grid in CollectionView

I am working on an application that utilizes the NHL API. I have a page that displays the schedule. By default, it loads the current day's games. I have a DatePicker in the 'CollectionView.Header', then a Grid within the ScheduleTemplate to display the data. If I select a new date in the DatePicker, it fires off the Property "get" process and loads the latest data into my "ObservableGames" List as expected, but the Grid clears completely and I just have a DatePicker left with an empty screen.
SchedulePage.xaml View:
<RefreshView Command="{Binding UpdateScheduleCommand}" IsRefreshing="{Binding IsRefreshing}">
<CollectionView Margin="20"
ItemsSource="{Binding ObservableGames}"
ItemTemplate="{StaticResource ScheduleTemplate}"
SelectionMode="Single">
<CollectionView.Header>
<Grid>
<DatePicker Grid.ColumnSpan="4" HorizontalOptions="Center" Date="{Binding SelectedDatePickerDate, Mode=TwoWay}" />
</Grid>
</CollectionView.Header>
</CollectionView>
</RefreshView>
App.xaml DataTemplate:
<DataTemplate x:Key="ScheduleTemplate">
<Grid Padding="8" RowDefinitions="Auto,Auto" ColumnDefinitions=".1*,.5*,.2*,.2*">
<Image Grid.Row="0" Grid.Column="0" Source="{Binding AwayTeamLogo, Mode=TwoWay}" HeightRequest="20" WidthRequest="20" HorizontalOptions="Center" VerticalOptions="Center" />
<Label Grid.Row="0" Grid.Column="1" Text="{Binding AwayAbbreviatedName, Mode=TwoWay}" HorizontalOptions="Start" />
<Label Grid.Row="0" Grid.Column="2" Text="{Binding AwayGoals, Mode=TwoWay}" HorizontalOptions="End" />
<Label Grid.Row="0" Grid.Column="3" Text="{Binding GameStatusString, Mode=TwoWay}" HorizontalOptions="End" />
<Image Grid.Row="1" Grid.Column="0" Source="{Binding HomeTeamLogo, Mode=TwoWay}" HeightRequest="20" WidthRequest="20" HorizontalOptions="Center" VerticalOptions="Center" />
<Label Grid.Row="1" Grid.Column="1" Text="{Binding HomeAbbreviatedName, Mode=TwoWay}" HorizontalOptions="Start" />
<Label Grid.Row="1" Grid.Column="2" Text="{Binding HomeGoals, Mode=TwoWay}" HorizontalOptions="End" />
<Grid.GestureRecognizers>
<TapGestureRecognizer
NumberOfTapsRequired="1"
Command="{Binding Source={RelativeSource AncestorType={x:Type viewModels:ScheduleViewModel}}, Path=GameTapped}"
CommandParameter="{Binding .}">
</TapGestureRecognizer>
</Grid.GestureRecognizers>
</Grid>
</DataTemplate>
ViewModel:
class ScheduleViewModel : INotifyPropertyChanged
{
public DateTime? _selectedDatePickerDate;
bool isRefreshing;
public ObservableCollection<Game> ObservableGames { get; private set; }
public DateTime DatePickerDate { get; set; }
public DateTime CurrentScheduleDate { get; set; }
public Command<Game> GameTapped { get; }
public Command<DateTime?> DatePickerTapped { get; }
public ICommand UpdateScheduleCommand => new Command(async () => await SetScheduleDataAsync());
public bool IsRefreshing
{
get
{
return isRefreshing;
}
set
{
isRefreshing = value;
OnPropertyChanged();
}
}
public DateTime? SelectedDatePickerDate
{
get => _selectedDatePickerDate;
set
{
SetProperty(ref _selectedDatePickerDate, value);
OnDatePickerSelected(value);
}
}
public ScheduleViewModel()
{
ObservableGames = new ObservableCollection<Game>();
GameTapped = new Command<Game>(OnGameSelected);
DatePickerTapped = new Command<DateTime?>(OnDatePickerSelected);
OnPropertyChanged(nameof(ObservableGames));
DatePickerDate = DateTime.Today;
SetScheduleDataAsync();
}
protected bool SetProperty<T>(ref T backingStore, T value, [CallerMemberName] string propertyName = "", Action onChanged = null)
{
if (EqualityComparer<T>.Default.Equals(backingStore, value))
return false;
backingStore = value;
onChanged?.Invoke();
OnPropertyChanged(propertyName);
return true;
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
async void OnGameSelected(Game game)
{
await Shell.Current.GoToAsync($"scheduledetails?gameLink={game.link}");
}
private void OnDatePickerSelected(DateTime? gameDate)
{
if (null != gameDate)
{
DatePickerDate = gameDate.Value;
SetScheduleDataAsync();
}
}
private async Task SetScheduleDataAsync()
{
IsRefreshing = true;
if (DatePickerDate != CurrentScheduleDate)
{
ObservableGames.Clear();
ScheduleData.LeagueSchedule = ScheduleData.GetSchedule(-1, DatePickerDate, null, string.Empty);
try
{
if ((null != ScheduleData.LeagueSchedule) && (null != ScheduleData.LeagueSchedule.dates) && (ScheduleData.LeagueSchedule.dates.Count > 0)
&& (null != ScheduleData.LeagueSchedule.dates[0]) && (ScheduleData.LeagueSchedule.dates[0].games.Count > 0))
{
ObservableGames = new ObservableCollection<Game>(ScheduleData.LeagueSchedule.dates[0].games);
for (int i = 0; i < ObservableGames.Count; i++)
{
if ((null != ObservableGames[i]) && (null != ObservableGames[i].status) && (!string.IsNullOrEmpty(ObservableGames[i].status.detailedState)))
{
switch (ObservableGames[i].status.detailedState.ToLower())
{
case "final":
ObservableGames[i].AwayGoals = ObservableGames[i].teams.away.score;
ObservableGames[i].HomeGoals = ObservableGames[i].teams.home.score;
ObservableGames[i].GameStatusString = ObservableGames[i].status.detailedState;
break;
case "in progress":
LiveGame liveGame = GameData.GetLiveGame(ObservableGames[i].link);
if (null != liveGame)
{
ObservableGames[i].AwayGoals = liveGame.liveData.linescore.teams.away.goals;
ObservableGames[i].HomeGoals = liveGame.liveData.linescore.teams.home.goals;
ObservableGames[i].GameStatusString = liveGame.liveData.linescore.currentPeriodTimeRemaining + " " + liveGame.liveData.linescore.currentPeriodOrdinal;
}
break;
case "postponed":
ObservableGames[i].GameStatusString = "Postponed";
break;
default:
ObservableGames[i].GameStatusString = ObservableGames[i].gameDate.ToLocalTime().ToShortTimeString();
break;
}
}
}
}
}
catch (Exception e)
{
}
finally
{
CurrentScheduleDate = DatePickerDate;
IsRefreshing = false;
}
}
}
}
I have tried using multiple Views, moved logic around and updated access modifiers. I have even debugged and the ObservableGames object does get updated with the new set of games based on the DatePicker Selection... . I just don't see it in the Grid.

Conditional binding two properties to one Textbox

Hello Dear Programmers
I decided to learn MVVP pattern using C# language. That is why I have one question for you. I have a very simple application which consists of 5 textboxes and one button. It is not finished yet.
What I achieved:
When I write some text in first textbox (Employee Name), dynamic
search launches and all matched records appear in a list.
When I click a record in a list, information appears in textboxes.
What I want to achieve:
When I write some text in first textbox (Employee Name), dynamic
search launches and all matched records appear in a list.
When I click a record in a list, information appears in textboxes.
When I edit first textbox (Employee Name), Employee Name in a list
should not be changed. (Only after button click).
Observations:
I read about Multibinding, Converters and UpdateSourcetrigger: Explicit and Propertychanged. I tried to multibind a textbox TextboxEmployeeName. When I set PropertyChanged, Dynamic search works but Employee Name in a list is changed when I write in Textbox, but when I set Explicit, Employee Name in a list does not change (what I want to achieve) but dynamic search does not work.
My question is: How to set adequate UpdateSourceTrigger according to condition?
If (Record is not selected)
{
UpdateSourceTrigger = PropertyChanged
}
Else If (Record is selected)
{
UpdateSourceTrigger = Explicit
}
I dont know if I take a good way to solve my problem. Maybe you know better solution? Could you help me? Below I placed my entire code:
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
}
}
Hmm, maybe this solution will be okay for you?
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; }
}
}
And 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>
I have solved my problem on my own. I have placed my entire code below :)
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
}
}

How to Display and select items in a Datagrid ComboBox with WPF C#, using MVVM

I want to be able to choose either "true" or "false"(boolean) from a ComboBox that is within a wpf Datagrid and be able to save that choice to my database.
I want to be able to indicate inside of a column if the row is "Active" or not through a boolean variable saved to my database as a bit(1 = true; 0 = false).
Here is my create table statement:
Create Table Statement(AccountType)
I populate the datagrid using an ObservableCollection as follows:
protected override void Get()
{
using (var dbContext = new IEMASEntitiesDataContext())
{
var accountType = from s in dbContext.AccountTypes select s;
var observable = new ObservableCollection<AccountType>(accountType);
Collection = observable;
}
}
My XAML code is as follows:
<DockPanel DataContext="{StaticResource ResourceKey=AccountTypeViewModel}" LastChildFill="True">
<ToolBar DockPanel.Dock="Top">
<Button Content="Display" Command="{Binding GetCommand}" Width="78"/>
<Button Content="Save" Command="{Binding SaveCommand}" Width="78"/>
</ToolBar>
<Grid>
<GroupBox x:Name="AccountTypeGroupBox">
<DataGrid x:Name="DataGridAccountType" ItemsSource="{Binding Collection}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="AccountType" Width="150" Binding="{Binding Path=AccountTypeName, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridComboBoxColumn Header="Active" Width="100" SelectedValueBinding="{Binding StatusList, UpdateSourceTrigger=PropertyChanged}" SelectedValuePath="AccountTypeId" DisplayMemberPath="Active"/>
<DataGridTemplateColumn Width="50" Header="Delete">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="btnDelete" Content="Delete" Command="{Binding DeleteCommand}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</GroupBox>
</Grid>
</DockPanel>
It doesn't work. Nothing displays within the comboboxes, and I don't know how to save the selected item to the SQL Server database when it does display. I'd appreciate some help, please. I am using LINQ TO SQL. I am a newbie :-(.
As I can understand the problem is how to bind some XAML resource as a combo ItemsSource and in addtion how to binnd the selected value of a combo to the model behind the DataGrid row.
1. List item:
<Window x:Class="SoDataGridProjectsHelpAttempt.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:soDataGridProjectsHelpAttempt="clr-namespace:SoDataGridProjectsHelpAttempt"
xmlns:system="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<x:Array x:Key="CountriesArray" Type="soDataGridProjectsHelpAttempt:Country">
<soDataGridProjectsHelpAttempt:Country CountryName="Germany" CountryPop="150k"/>
<soDataGridProjectsHelpAttempt:Country CountryName="France" CountryPop="125k"/>
<soDataGridProjectsHelpAttempt:Country CountryName="Belarus" CountryPop="165k"/>
</x:Array>
<x:Array x:Key="StatusArray" Type="soDataGridProjectsHelpAttempt:ActivityStatus">
<soDataGridProjectsHelpAttempt:ActivityStatus VerbalStatus="Yes" BoolStatus="True"/>
<soDataGridProjectsHelpAttempt:ActivityStatus VerbalStatus="No" BoolStatus="False"/>
</x:Array>
</Window.Resources>
<Window.DataContext>
<soDataGridProjectsHelpAttempt:DataGridMainDataContext/>
</Window.DataContext>
<Grid>
<DataGrid ItemsSource="{Binding Collection}" AutoGenerateColumns="False" CanUserAddRows="True">
<DataGrid.Columns>
<DataGridTextColumn Width="Auto" Binding="{Binding UName}"/>
<DataGridComboBoxColumn Header="Country" DisplayMemberPath="CountryName"
ItemsSource="{StaticResource CountriesArray}" Width="Auto"
SelectedItemBinding="{Binding CountryData}"/>
<!--<DataGridComboBoxColumn Header="ActivityStatus" Width="Auto" ItemsSource="{StaticResource StatusArray}"
SelectedValueBinding="{Binding IsActive}" SelectedValuePath="BoolStatus" DisplayMemberPath="VerbalStatus"/>-->
<DataGridComboBoxColumn Header="ActivityStatus" SelectedItemBinding="{Binding IsActive, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<DataGridComboBoxColumn.ItemsSource>
<x:Array Type="system:Boolean">
<system:Boolean>True</system:Boolean>
<system:Boolean>False</system:Boolean>
</x:Array>
</DataGridComboBoxColumn.ItemsSource>
</DataGridComboBoxColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
DataGrid viewmodel:
public class DataGridMainDataContext
{
public DataGridMainDataContext()
{
Collection = new ObservableCollection(new List
{
new UserData
{
UName = "Greg",
IsActive = false,
},
new UserData
{
UName = "Joe",
IsActive = false,
},
new UserData
{
UName = "Iv",
IsActive = false,
}
});
}
public ObservableCollection<UserData> Collection { get; set; }
}
Models:
public class UserData : BaseObservableObject
{
private string _uName;
private object _countryData;
private bool _isActive;
public bool IsActive
{
get { return _isActive; }
set
{
_isActive = value;
OnPropertyChanged();
}
}
public string UName
{
get { return _uName; }
set
{
_uName = value;
OnPropertyChanged();
}
}
public object CountryData
{
get { return _countryData; }
set
{
_countryData = value;
OnPropertyChanged();
}
}
}
public class ActivityStatus:BaseObservableObject
{
private bool _boolStatus;
private string _verbalStatus;
public bool BoolStatus
{
get { return _boolStatus; }
set
{
_boolStatus = value;
OnPropertyChanged();
}
}
public string VerbalStatus
{
get { return _verbalStatus; }
set
{
_verbalStatus = value;
OnPropertyChanged();
}
}
}
public class Country : BaseObservableObject
{
private string _countryName;
private string _countryPop;
public string CountryName
{
get { return _countryName; }
set
{
_countryName = value;
OnPropertyChanged();
}
}
public string CountryPop
{
get { return _countryPop; }
set
{
_countryPop = value;
OnPropertyChanged();
}
}
public Country() { }
public Country(string n, string d)
{
this.CountryName = n;
this.CountryPop = d;
}
}
Hope it will help you.
regards,

Conditional CanUserAddRows in a DataGrid in WPF

Suppose I have a ComboBox like :
<ComboBox SelectedValue="{Binding DataContext.CanUserAddMultipleRows,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Page}},
Converter={StaticResource yesNoToBooleanConverter}}">
<ComboBoxItem>Yes</ComboBoxItem>
<ComboBoxItem>No</ComboBoxItem>
</ComboBox>
Here is the Converter :
public class YesNoToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!(value == null || value == DependencyProperty.UnsetValue))
{
if ((bool)value == true)
{
return "Yes";
}
else
{
return "No";
}
}
else
{
return "No";
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!(value == null || value == DependencyProperty.UnsetValue))
{
if (((ComboBoxItem)value).Content.ToString() == "Yes")
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
}
Now I have a DataGrid :
<DataGrid Grid.Row="7" Grid.Column="1" Grid.ColumnSpan="2" AutoGenerateColumns="False"
CanUserAddRows="{Binding DataContext.CanUserAddMultipleRows,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Page}}}"
ItemsSource="{Binding DataContext.MyObject,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Page}}}">
<DataGrid.Columns>
<DataGridTextColumn Header="Quantity" Binding="{Binding Quantity}"></DataGridTextColumn>
<DataGridTextColumn Header="Rate" Binding="{Binding Rate}"></DataGridTextColumn>
<DataGridTextColumn Header="Amount" Binding="{Binding Amount}"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
Now I want to provide 1 row by default to the users, so that if CanUserAddRows = false, then also they should be able to add 1 item to DataGrid. If CanUserAddRows = true, then user can have any number of rows he wants.
This thing might be simple but I am new to DataGrid. So, i asked this question.
In my example, there is a MayUserAddRows property of bool type. If MayUserAddRows == true then User can add as many records, but if MayUserAddRows == false then he will be able to fill only one record.
Also has CanUserAddRows property, which directly Binding with the property of DataGrid.CanUserAddRows.
Properties that are in the ViewModel implement the INotifyPropertyChanged interface via NotificationObject. He has an event PropertyChangedEventHandler(propertyName) which informs on notification properties. The key logic is here:
private void MyViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName.Equals("MayUserAddRows"))
{
// The MayUserAddRows property is changed
if (MyViewModel.MayUserAddRows == true)
{
// Allow to add a lot of records
MyViewModel.CanUserAddRows = true;
}
if (MyViewModel.MayUserAddRows == false)
{
// Prohibit the addition
MyViewModel.CanUserAddRows = false;
// And add the empty row
AddEmptyRow(MyViewModel.MyCollection);
}
}
}
Below is a full example:
XAML
<Window x:Class="ConditionalCanUserAddRows.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:this="clr-namespace:ConditionalCanUserAddRows"
WindowStartupLocation="CenterScreen"
Title="MainWindow" Height="300" Width="325">
<Grid>
<CheckBox Content="{Binding Path=IsChecked,
RelativeSource={RelativeSource Mode=Self}}"
ContentStringFormat="May user add rows - {0}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
IsChecked="{Binding Path=MayUserAddRows}" />
<Button Content="Clear"
VerticalAlignment="Top"
HorizontalAlignment="Right"
Click="Clear_Click" />
<DataGrid Name="SimpleDataGrid"
Width="200"
Height="200"
CanUserResizeColumns="False"
AutoGenerateColumns="False"
RowHeaderWidth="0"
CanUserAddRows="{Binding Path=CanUserAddRows, Mode=TwoWay}"
ItemsSource="{Binding Path=MyCollection}">
<DataGrid.Columns>
<DataGridTextColumn Width="1.5*"
Header="Name"
Binding="{Binding Path=Name}" />
<DataGridTextColumn Header="Age"
Width="1.5*"
FontSize="14"
Binding="{Binding Path=Age}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
Code-behind
public partial class MainWindow : Window
{
ViewModel MyViewModel = new ViewModel();
public MainWindow()
{
InitializeComponent();
this.DataContext = MyViewModel;
MyViewModel.MyCollection = new ObservableCollection<Person>();
MyViewModel.MyCollection.Add(new Person()
{
Age = 22,
Name = "Nick",
});
MyViewModel.MyCollection.Add(new Person()
{
Age = 11,
Name = "Sam",
});
MyViewModel.MyCollection.Add(new Person()
{
Name = "Kate",
Age = 15,
});
AddEmptyRow(MyViewModel.MyCollection);
MyViewModel.PropertyChanged += new PropertyChangedEventHandler(MyViewModel_PropertyChanged);
}
private void MyViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName.Equals("MayUserAddRows"))
{
if (MyViewModel.MayUserAddRows == true)
{
MyViewModel.CanUserAddRows = true;
}
if (MyViewModel.MayUserAddRows == false)
{
MyViewModel.CanUserAddRows = false;
AddEmptyRow(MyViewModel.MyCollection);
}
}
}
#region AddEmptyRow
private void AddEmptyRow(ObservableCollection<Person> collection)
{
collection.Add(new Person()
{
Name = "",
Age = 0,
});
}
#endregion
#region Clear
private void Clear_Click(object sender, RoutedEventArgs e)
{
MyViewModel.MyCollection.Clear();
}
#endregion
}
#region ViewModel
public class ViewModel : NotificationObject
{
#region MyCollection
public ObservableCollection<Person> MyCollection
{
get;
set;
}
#endregion
#region CanUserAddRows
private bool _canUserAddRows = false;
public bool CanUserAddRows
{
get
{
return _canUserAddRows;
}
set
{
_canUserAddRows = value;
NotifyPropertyChanged("CanUserAddRows");
}
}
#endregion
#region MayUserAddRows
private bool _mayUserAddRows = false;
public bool MayUserAddRows
{
get
{
return _mayUserAddRows;
}
set
{
_mayUserAddRows = value;
NotifyPropertyChanged("MayUserAddRows");
}
}
#endregion
}
#endregion
#region Model
public class Person
{
public string Name
{
get;
set;
}
public int Age
{
get;
set;
}
}
#endregion
#region NotificationObject
public class NotificationObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
#endregion
Output
MayUserAddRows="False"
MayUserAddRows="True"
Project compiled under the Visual Studio 2010, this example is fully fits the MVVM style.
This project available here

How to set the ItemSource of a Datagrid to a collection inside an object using MVVM

I have a ComboBox that holds a list of StrategyViewModels. The StrategyViewModel has an ObservableCollection of StrategyParameterViewModels inside of it. I have a StrategyViewModel called SelectedStrategy that I bound to the SelectedItem property on the combobox. When the user selects a Strategy from the ComboBox I would like to set the itemsource of a datagrid to the StrategyParameters inside that Strategy. I've tried all different ways, but nothing seems to work.
Here's the XAML:
<ComboBox Height="23" Margin="0,12,0,0" Name="cbxStrats" VerticalAlignment="Top" ItemsSource="{Binding Strategies}" DisplayMemberPath="Name" SelectedItem="{Binding Path=SelectedStrategy,Mode=TwoWay}" />
<DataGrid AutoGenerateColumns="False" Margin="12,97,14,35" Name="dgSettings" ItemsSource="{Binding SelectedStrategy.Parameters, Mode=TwoWay}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name}" IsReadOnly="True"/>
<DataGridTextColumn Header="Value" Binding="{Binding Path=Value}" IsReadOnly="False"/>
</DataGrid.Columns>
</DataGrid>
Here is the Strategy ViewModel:
public class StrategyViewModel : ViewModelBase
{
public StrategyObject Strategy { get; set; }
public int Id
{
get { return Strategy.Id; }
set
{
if (value == Strategy.Id)
return;
Strategy.Id = value;
OnPropertyChanged("Id");
}
}
public string Name
{
get { return Strategy.Name; }
set
{
if (value == Strategy.Name)
return;
Strategy.Name = value;
OnPropertyChanged("Name");
}
}
public ObservableCollection<StrategyParameterViewModel> Parameters { get { return _parameters; } }
public ObservableCollection<StrategyParameterViewModel> _parameters;
public StrategyViewModel()
{
Strategy = new StrategyObject();
_parameters = new ObservableCollection<StrategyParameterViewModel>();
}
public StrategyViewModel(StrategyObject o, IEnumerable<StrategyParameterObject> pms)
{
Strategy = o;
_parameters = new ObservableCollection<StrategyParameterViewModel>();
foreach (StrategyParameterObject s in pms)
{
_parameters.Add(new StrategyParameterViewModel(s));
}
}
}
And here is the StrategyParameter ViewModel:
public class StrategyParameterViewModel : ViewModelBase
{
public StrategyParameterObject StrategyParameter { get; set; }
public int Id
{
get { return StrategyParameter.Id; }
set
{
if (value == StrategyParameter.Id)
return;
StrategyParameter.Id = value;
OnPropertyChanged("Id");
}
}
public int StrategyId
{
get { return StrategyParameter.StrategyId; }
set
{
if (value == StrategyParameter.StrategyId)
return;
StrategyParameter.StrategyId = value;
OnPropertyChanged("StrategyId");
}
}
public string Name
{
get { return StrategyParameter.Name; }
set
{
if (value == StrategyParameter.Name)
return;
StrategyParameter.Name = value;
OnPropertyChanged("Name");
}
}
public string Value
{
get { return StrategyParameter.Value; }
set
{
if (value == StrategyParameter.Value)
return;
StrategyParameter.Value = value;
OnPropertyChanged("Value");
}
}
public StrategyParameterViewModel()
{
StrategyParameter = new StrategyParameterObject();
}
public StrategyParameterViewModel(StrategyParameterObject o)
{
StrategyParameter = o;
}
}
The problem is that you are trying to set up a two way binding with a read-only property. You need to either add a setter for SelectedStrategy.Parameters, or use a OneWay binding on the datagrid itemssource.
Off the top of my head, I don't think you're doing anything wrong with regards to your XAML.
Data Binding is notoriously tricky. I suggest adding PresentationTraceSources to get more debug information as to what is being found. This will ship several lines of data about binding results to your Output window.
<ComboBox Height="23" Margin="0,12,0,0" Name="cbxStrats" VerticalAlignment="Top" DisplayMemberPath="Name">
<ComboBox.ItemsSource>
<Binding Path="Strategies" PresentationTraceSources.TraceLevel="High"/>
</ComboBox.ItemsSource>
<ComboBox.SelectedItem>
<Binding Path="SelectedStrategy" Mode="TwoWay" PresentationTraceSources.TraceLevel="High"/>
</ComboBox.SelectedItem>
</ComboBox>
<DataGrid AutoGenerateColumns="False" Margin="12,97,14,35" Name="dgSettings">
<DataGrid.ItemsSource>
<Binding Path="SelectedStrategy.Parameters" Mode="TwoWay" PresentationTraceSources.TraceLevel="High"/>
</DataGrid.ItemsSource>
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name}" IsReadOnly="True"/>
<DataGridTextColumn Header="Value" Binding="{Binding Path=Value}" IsReadOnly="False"/>
</DataGrid.Columns>
</DataGrid>
In addition, WPF Inspector can help, as you can tweak Data Binding expressions in real time when running your actual app. http://wpfinspector.codeplex.com/

Categories

Resources