Binding data from textbox to datagrid - c#

I'm making a Contact info program, where users can enter there name, age and birthday and some other things into textboxes. When you click ok, I want the data to be put into the DataGrid.
First I have my MainWindow, which opens a new window called CreateContact when you press the Create new contact button:
CreateContact cc = new CreateContact();
cc.ShowDialog();
then a new window open, where you type your name and age and choose the birthdate. Then you click OK:
private void cmdOk_Click(object sender, RoutedEventArgs e)
{
MainWindow m = new MainWindow();
m.name = txtName.Text;
m.age = txtAge.Text;
m.birthDate = dpBirthdate.Text;
m.ShowContacts()
}
which should run my method ShowContacts in my MainWindow:
public string name;
public string age;
public string birthDate;
public void ShowContacts()
{
try
{
dgContacts.ItemsSource = LoadContactData();
}
catch (Exception e)
{
MessageBox.Show("" + e);
}
}
private List<ContactData> LoadContactData()
{
List<ContactData> list = new List<ContactData>();
list.Add(new ContactData()
{
Name = name,
Age = age,
BirthDate = birthDate
});
return list;
}
public class ContactData
{
public string Name { get; set; }
public string Age { get; set; }
public string BirthDate { get; set; }
}
But nothing happens, I get no data in the DataGrid. I hope someone can tell me what is wrong. I have really tried searching a lot on what is causing the DataGrid to show no data.

Assuming the dgContacts is the datagrid view control, you have to call the following command to ensure that the data is bound
dgContacts.DataBind();
The procedure is similar to the one that is explained here.
In case you have debugged the code, and this suggestion is not working, please debug and post whether the data that is bound to the control.

Short answer: looks like you're not firing the PropertyChanged event when you change the ItemsSource in ShowContacts.
Long answer: you should really look into MVVM. You should just create a ViewModel that maintains a list of ContactData, and bind to that list in your XAML (also databind your Contact dialog to a ContactData object):
var contact = new ContactData();
var cc = new CreateContact { Datacontext = contact };
cc.ShowDialog();
// ok button has been hit at this point,
// you can check for cancel if you want
(List<ContactData>)(dgContacts.ItemsSource).Add(contact);
// may still need to fire PropertyChanged here depending on binding

Okay, here is all the xaml and classes i use in the program. I really hope someone can help tell, what is wrong and why it wont show any data in the datagrid.
MainWindow.xaml:
<Window x:Class="KontaktInfo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid AutoGenerateColumns="True" Name="dgContacts" HorizontalAlignment="Left" Margin="0,95,0,0" VerticalAlignment="Top" Height="225" Width="517"/>
<Button x:Name="cmdCreateContact" Content="Opret Kontakt" HorizontalAlignment="Left" Margin="0,68,0,0" VerticalAlignment="Top" Width="80" Click="cmdCreateContact_Click"/>
<Button x:Name="cmdDeleteContact" Content="Slet Kontakt" HorizontalAlignment="Left" Margin="85,68,0,0" VerticalAlignment="Top" Width="80"/>
</Grid>
MainWindow.cs:
using System;
using System.Collections.Generic;
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 KontaktInfo
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public string name;
public string age;
public string birthDate;
public MainWindow()
{
InitializeComponent();
}
private void cmdCreateContact_Click(object sender, RoutedEventArgs e)
{
CreateContact cc = new CreateContact();
cc.ShowDialog();
}
public void ShowContacts()
{
try
{
dgContacts.ItemsSource = LoadContactData();
}
catch (Exception e)
{
MessageBox.Show("" + e);
}
}
private List<ContactData> LoadContactData()
{
List<ContactData> list = new List<ContactData>();
list.Add(new ContactData()
{
Name = name,
Age = age,
BirthDate = birthDate
});
return list;
}
}
public class ContactData
{
public string Name { get; set; }
public string Age { get; set; }
public string BirthDate { get; set; }
}
}
CreateContact.xaml:
<Window x:Class="KontaktInfo.CreateContact"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CreateContact" Height="403" Width="300">
<Grid>
<Label Content="Navn" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="txtName" HorizontalAlignment="Left" Height="23" Margin="10,36,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="272"/>
<Label Content="Alder" HorizontalAlignment="Left" Margin="10,64,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="txtAge" HorizontalAlignment="Left" Height="23" Margin="10,90,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="272"/>
<Label Content="Fødselsdag" HorizontalAlignment="Left" Margin="10,118,0,0" VerticalAlignment="Top"/>
<Button Name="cmdOk" Content="OK" HorizontalAlignment="Left" Margin="127,341,0,0" VerticalAlignment="Top" Width="75" Click="cmdOk_Click"/>
<Button Name="cmdCancel" Content="Annuller" HorizontalAlignment="Left" Margin="207,341,0,0" VerticalAlignment="Top" Width="75"/>
<DatePicker Name="dpBirthdate" HorizontalAlignment="Left" Margin="10,144,0,0" VerticalAlignment="Top"/>
</Grid>
</Window>
CreateContact.cs:
using System;
using System.Collections.Generic;
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.Shapes;
namespace KontaktInfo
{
/// <summary>
/// Interaction logic for CreateContact.xaml
/// </summary>
public partial class CreateContact : Window
{
public CreateContact()
{
InitializeComponent();
}
private void cmdOk_Click(object sender, RoutedEventArgs e)
{
MainWindow m = new MainWindow();
m.name = txtName.Text;
m.age = txtAge.Text;
m.birthDate = dpBirthdate.Text;
m.ShowContacts();
}
}
}

Related

How to change field to original value using a "reset" button in wpf

I have a class that has several properties, one of which is editable, another of which is calculated based on the editable value. I want to initialize the editable value with something and allow the user to change it however they wish. However, I also want to have a reset button that puts the original value back into the textbox. I have a third variable that stores the value of the original number. However, I am not sure how I am supposed to access the object when the reset button is clicked to put the value back into the textbox. I've put the relevant code below (if I shouldn't be posting everything please let me know, still new to stackoverflow how-to):
Main Window
C#
using System;
using System.Collections.Generic;
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;
using HDR_BED_Calc_local.Testers;
using HDR_BED_Calc_local.Helpers;
namespace HDR_BED_Calc_local
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//var window = new MainWindow();
this.DataContext = new fraction_doses(800, 700, 900, 800, 900, 1, 3);
}
}
}
XAML
<Window x:Class="HDR_BED_Calc_local.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:HDR_BED_Calc_local"
xmlns:uctesters="clr-namespace:HDR_BED_Calc_local.Testers"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<uctesters:fx_tester x:Name="fxtester_UC"/>
</Grid>
</Window>
Custom user control
C#
using System;
using System.Collections.Generic;
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;
using HDR_BED_Calc_local.Helpers;
namespace HDR_BED_Calc_local.Testers
{
/// <summary>
/// Interaction logic for fx_tester.xaml
/// </summary>
public partial class fx_tester : UserControl
{
public fx_tester()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// What do I put here??
}
}
}
XAML
<UserControl x:Class="HDR_BED_Calc_local.Testers.fx_tester"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:HDR_BED_Calc_local.Testers"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" Background="White">
<StackPanel HorizontalAlignment="Center">
<StackPanel Orientation="Horizontal">
<TextBlock xml:space="preserve">Fraction: </TextBlock>
<TextBlock Text="{Binding Path=fraction_number}"></TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock xml:space="preserve">Current Dose: </TextBlock>
<TextBox x:Name="curr_fx_tb" Text="{Binding Path=editable_fraction_dose, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock xml:space="preserve">EQD2: </TextBlock>
<TextBlock Text="{Binding Path=this_fx_brachy_EQD2, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
<Button Content="Reset" Click="Button_Click"/>
</StackPanel>
</UserControl>
Helper function with class
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace HDR_BED_Calc_local.Helpers
{
internal class fraction_doses : INotifyPropertyChanged
{
public int fraction_number { get; set; }
public double alpha_beta { get; }
private double _editable_fraction_dose;
public double editable_fraction_dose
{
get { return _editable_fraction_dose; }
set
{
_editable_fraction_dose = value;
calc_EQD2();
this.OnPropertyChanged("editable_fraction_dose");
}
}
public double actual_fraction_dose { get; }
public double pear_plan_dose { get; }
public double IMRT_plan_dose { get; }
public double max_dose_limit { get; }
public double preferred_dose_limit { get; }
private double _this_fx_brachy_EQD2;
public double this_fx_brachy_EQD2
{
get { return this._this_fx_brachy_EQD2; }
set
{
this._this_fx_brachy_EQD2 = value;
this.OnPropertyChanged("this_fx_brachy_EQD2");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public fraction_doses(double current_dose, double pear_dose, double IMRT_dose, double max_dose_limit, double preferred_dose_limit, int fraction_number, int alpha_beta)
{
this.alpha_beta = alpha_beta;
this.actual_fraction_dose = current_dose;
this.editable_fraction_dose = current_dose;
this.pear_plan_dose = pear_dose;
this.IMRT_plan_dose = IMRT_dose;
this.max_dose_limit = max_dose_limit;
this.preferred_dose_limit = preferred_dose_limit;
this.fraction_number = fraction_number;
}
public void calc_EQD2()
{
// EQD2 is always reported in Gray even though we will be reporting cGy
double dose_Gy = this.editable_fraction_dose/100;
this.this_fx_brachy_EQD2 = Math.Round(1 * dose_Gy * (1+ dose_Gy / alpha_beta)/(1+2/alpha_beta), 2);
}
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
You can try the following:
private void Button_Click(object sender, RoutedEventArgs e)
{
// What do I put here??
var dc = (fraction_doses ) this.DataContext:
if(dc!=null)
dc.Clear();
}
in your fraction_doses class add the method that clears the properties
public void Clear(){
this.MyProperty = MY_DEFAULT_VALUE;
//clear other properties..
}

How I can modify the Selected text of Combobox?

I'm newer to C# for UI WPF and I would like to set the value of Combobox?
cbx1.SelectedItem = "test 1";
This line show me every time null ( not an exception ) but the selectedItem is empty.
<telerik:RadComboBox Background="White" Foreground="{DynamicResource TitleBrush}" x:Name="cbx1" AllowMultipleSelection="True" VerticalAlignment="Center" HorizontalAlignment="Right" Width="200" Grid.Row="1" Grid.Column="0" Margin="0,14,11,14" Height="22"/>
Update :
I think that my question is not clear , I will give an example :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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;
using System.Collections.ObjectModel;
namespace WpfApplication2
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
ObservableCollection<Person> myPersonList = new ObservableCollection<Person>();
Person personJobs = new Person("Steve", "Jobs");
Person personGates = new Person("Bill", "Gates");
myPersonList.Add(personJobs);
myPersonList.Add(personGates);
MyComboBox.ItemsSource = myPersonList;
MyComboBox.SelectedItem = personGates;
}
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Person(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
}
}
In this code , if myCombobox.displayMemberPath = FirstName , How can I set the selected FirstName???
I do not have Teleriks Combobox, so I am using the standard Combobox here.
You should also know that XAML is very quiet, it do not throw an exception, but you will probably find an error message in the Output window.
This example is following the MVVM pattern. This means that you will find most of the code in the PersonViewModel class (the "View Model") where the properties are bound to the View. (I am not using the Model here, but that could be a data source class).
The PersonViewModel is inheriting the VMBase where the that notifies the View about changes in properties.
So, to your problem: I have added a property "SelectedPerson". This property is bound to the SelectedItem in the control. So each time you change the item in the combobox the SelectedPerson will contain the selected Person object.
I have also added a button "Select Steve" that will, In the PersonViewModel, find the Person object with firstname = "Steve" and set the SelectedPerson to that object. The Combobox will change to "Steve".
Window1.xaml
<Window x:Class="SO65149368.Window1"
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:SO65149368"
mc:Ignorable="d"
Title="Window1" Height="450" Width="800">
<StackPanel>
<ComboBox Name="MyComboBox" Width="300" HorizontalAlignment="Left" Margin="5"
ItemsSource="{Binding myPersonList}"
DisplayMemberPath="FirstName"
SelectedItem="{Binding SelectedPerson, Mode=TwoWay}"/>
<StackPanel Orientation="Horizontal">
<Button x:Name="SelectSteve" Content="Select Steve" Click="SelectSteve_Click"
Margin="5"/>
</StackPanel>
</StackPanel>
</Window>
Window1.xaml.cs
using System.Windows;
namespace SO65149368
{
public partial class Window1 : Window
{
public PersonViewModel PersonViewModel = new PersonViewModel();
public Window1()
{
DataContext = PersonViewModel;
InitializeComponent();
}
private void SelectSteve_Click(object sender, RoutedEventArgs e)
{
PersonViewModel.SelectSteve();
}
}
}
PersonViewModel.cs
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
namespace SO65149368
{
public class PersonViewModel : VMBase
{
public ObservableCollection<Person> myPersonList { get; } = new ObservableCollection<Person>();
public PersonViewModel()
{
Person personJobs = new Person("Steve", "Jobs");
Person personGates = new Person("Bill", "Gates");
myPersonList.Add(personJobs);
myPersonList.Add(personGates);
SelectedPerson = personGates;
//MyComboBox.ItemsSource = myPersonList;
//MyComboBox.SelectedItem = personGates;
}
public Person SelectedPerson
{
get { return _selectedPerson; }
set
{
Set(ref _selectedPerson, value);
Debug.WriteLine("Selected person: " + SelectedPerson.FirstName + " " + SelectedPerson.LastName);
}
}
private Person _selectedPerson;
public void SelectSteve()
{
SelectedPerson = myPersonList.FirstOrDefault(p => p.FirstName == "Steve");
}
}
}
VMBase.cs
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace SO65149368
{
public abstract class VMBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool Set<T>(ref T field, T newValue, [CallerMemberName] string propertyName = null)
{
if (!EqualityComparer<T>.Default.Equals(field, newValue))
{
field = newValue;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
return true;
}
return false;
}
}
}

In a basic WPF project, how can I avoid making a wide scope class initialization?

This is a very basic question, and I'm certain the reason I haven't found an answer is because I'm not 100% positive how to google it.
I have a very simple project, where I want to use a class that contains my info.
public class MyInfo
{
public string name = String.Empty;
public string ssn = String.Empty;
public string dob = String.Empty;
}
very basic.
I have a xaml file with buttons, and I just want to set the value of the variables in my class, to the contents in my buttons. Here's the xaml.
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Name="name" Content="John Doe" HorizontalAlignment="Left" Margin="117,60,0,0" VerticalAlignment="Top" Width="75" Click="name_click"/>
<Button Name="ssn" Content="222-22-2222" HorizontalAlignment="Left" Margin="117,120,0,0" VerticalAlignment="Top" Width="75" Click="ssn_click"/>
<Button Name="dob" Content="June 1st 1992" HorizontalAlignment="Left" Margin="117,178,0,0" VerticalAlignment="Top" Width="75" Click="dob_click"/>
</Grid>
</Window>
The problem I'm having, is that the only way I know how to do this (being a total C# noob) is by having my class initialization in a super wide scope.
For example, here's my cs file with comments on what I initially did, but not what I think should be done.
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
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 WpfApplication1
{
public class MyInfo
{
public string name = String.Empty;
public string ssn = String.Empty;
public string dob = String.Empty;
}
// If i create a class instance here like this
//MyInfo infoTest = new MyInfo();
// then I can just set the values in the click functions like
//infoTest.dob = dob.Content.ToString();
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void name_click(object sender, RoutedEventArgs e)
{
//save name.content into MyInfo.name
}
private void ssn_click(object sender, RoutedEventArgs e)
{
//save ssn.content into MyInfo.ssn
}
private void dob_click(object sender, RoutedEventArgs e)
{
//save dob.Content into MyInfo.dob
}
}
}
I would think it would be better to create an instance of my class in the MainWindow class, after InitializeComponent();, but then I'm not certain how to get my values into the class object with a closed scope.
Just like this also you should use Auto-Implemented Properties instead of public fields:
public Window1()
{
InitializeComponent();
MyInfo myinfo = new MyInfo();
myinfo.Name = name.Content.ToString();
myinfo.Ssn = ssn.Content.ToString();
myinfo.Dob = dob.Content.ToString();
}
public class MyInfo
{
public string Name { get; set; }
public string Ssn { get; set; }
public string Dob { get; set; }
}
If you want to set properties after click buttons you should try this:
MyInfo myinfo = new MyInfo();
public Window1()
{
InitializeComponent();
}
Then:
private void name_Click(object sender, RoutedEventArgs e)
{
myinfo.Name = name.Content.ToString();
}
Another method of achieving this would be to make use of Binding.
public class MyInfo
{
public string Name { get; set; }
public string Ssn { get; set; }
public string Dob { get; set; }
}
public class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MyInfo();
}
...
And your XAML will look like this:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Name="name" Content="{Binding Name}" HorizontalAlignment="Left" Margin="117,60,0,0" VerticalAlignment="Top" Width="75"/>
<Button Name="ssn" Content="{Binding Ssn}" HorizontalAlignment="Left" Margin="117,120,0,0" VerticalAlignment="Top" Width="75"/>
<Button Name="dob" Content="{Binding Dob}" HorizontalAlignment="Left" Margin="117,178,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
This will allow you to avoid having to use Click events to set the properties of your object. You can find an excellent tutorial here.
The answer is already been marked, but I'd like to give you another POV using binding. Which i prefer to separate GUI/Business layer.
Some code:
public partial class MainWindow : Window
{
public class MyInfo
{
public string Name { get; set; }
public string Ssn { get; set; }
public string Dob { get; set; }
}
private MyInfo _myInfo;
public MainWindow()
{
InitializeComponent();
_myInfo = new MyInfo();
_myInfo.Name = "My name";
this.DataContext = _myInfo;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("My name is '" + _myInfo.Name + "'");
}
}
XAML
<Window x:Class="BindingExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel Width="200" VerticalAlignment="Center">
<TextBox Text="{Binding Name}" />
<TextBox Text="{Binding Ssn}" />
<TextBox Text="{Binding Dob}" />
<Button Content="Click me" Click="Button_Click" />
</StackPanel>
</Window>
It's even possible to update the TextBoxes from code (without writing directly to the Text property), assigning your class. Using the INotifyPropertyChanged

WPF Populating list, assigning on-click event handler with custom variables to pass

I'm populating a listBox, Each list item has a button.
I've got it populating text in to the list, but I'd like each button to have the correct event handler and the house number to be passed to it.
Here's the XAML code:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded" Background="#FFCBCBCB">
<Grid>
<Label Content="Welcome to the house manager" Height="28" HorizontalAlignment="Left" Margin="20,12,0,0" Name="label1" VerticalAlignment="Top" />
<ListBox Height="253" HorizontalAlignment="Left" Margin="10,46,0,0" VerticalAlignment="Top" Width="481" x:Name="houseList">
<ListBox.ItemTemplate>
<DataTemplate DataType="house">
<Button Click="choose_house(HOUSE NUMBER HERE)" Background="#FFBEBEBE" BorderThickness="0" Focusable="True" Width="459" BorderBrush="White" Padding="0">
<StackPanel Orientation="Vertical" Width="400" VerticalAlignment="Stretch">
<TextBlock Margin="0,5,0,0" Text="{Binding street}" HorizontalAlignment="Left" />
<TextBlock Margin="0,5,0,0" Text="{Binding postCode}" HorizontalAlignment="Left" />
</StackPanel>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Here's the code which populates the list at the moment:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
List<house> houseAddresses = new List<house>();
// Create a new house
for (var i = 1; i <= 10; i++)
{
house newHouse = new house();
newHouse.street = i + " Scale Hall Lane";
newHouse.postCode = "PR4 3TL";
newHouse.houseNumber = i;
houseAddresses.Add(newHouse);
}
// Go through each house and add them to the list
foreach (house houses in houseAddresses)
{
houseList.Items.Add(houses);
}
}
private void choose_house(object sender, RoutedEventArgs e)
{
MessageBox.Show("Clicked");
}
}
}
Here's my house class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WpfApplication1
{
class house
{
public string street { get; set; }
public string postCode { get; set; }
public int houseNumber { get; set; }
}
}
I've put Click="choose_house(HOUSE NUMBER HERE)" in the code on the button where the code would have the correct event handler.
Either cast your sender as a Button and get it's DataContext, or use a Command and bind the CommandParameter to the HouseNumber
private void choose_house(object sender, RoutedEventArgs e)
{
var ctrl = sender as Button;
var h = ctrl.DataContext as house; // Please capitalize your classes! :)
MessageBox.Show(h.houseNumber);
}
or
<Button Command="{Binding Path=DataContext.ChooseHouseCommand,
RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}"
CommandParameter="{Binding houseNumber}" ... />
What you can do on the click handler is:
private void choose_house(object sender, RoutedEventArgs e)
{
var button = sender as Button;
if (button != null)
{
var yourObject = button.DataContext as house;
if (yourObject != null)
{
//do stuff with your button
}
}
}

How to add an item from one datagrid to another then edit it in WPF

I have an issue when I try to use datagrid.items.add() to add items from one datagrid to another. Basically I have two data grids acting in a master slave relationship. The First DataGrid1 is used to display automatically generated columns and rows. The second datagrid, DataGrid2 will display the DataGrid1.SelectedItems when a specific button is clicked. Each time the button is clicked I'd like to have the selected items from DataGrid1 stay in DataGrid2 and each time the button is clicked more items get added to DataGrid2. I have been able to complete most of my requirements with the exception of the ability to edit cells on DataGrid2. When I double click a cell in DataGrid2 I get an exception that says "EditItem' is not allowed for this view". I have read a lot of posts about adding data to a ObservableCollection, ListCollectionView and so on but either I can not implement them in the correct manner or there not working for my situation. My code is as follows and by the way thx in advance
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid AutoGenerateColumns="False" Height="77" HorizontalAlignment="Left" Margin="27,12,0,0" Name="dataGrid1" VerticalAlignment="Top" Width="464" />
<Button Content="AddRow" Height="23" HorizontalAlignment="Left" Margin="27,107,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
<DataGrid AutoGenerateColumns="False" Height="140" HorizontalAlignment="Left" Margin="27,159,0,0" Name="dataGrid2" VerticalAlignment="Top" Width="464" />
</Grid>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 WpfApplication1
{
///
/// Interaction logic for MainWindow.xaml
///
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
dataGrid1.ItemsSource = idata;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
foreach (latlongobj item in dataGrid1.SelectedItems)
{
dataGrid2.Items.Add(item);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WpfApplication1
{
class latlonobj
{
public string name { get; set; }
public double Lat { get; set; }
public double Lon { get; set; }
}
}
Is this what you want?
public partial class MainWindow : Window
{
ObservableCollection dataGrid2Items = new ObservableCollection();
public MainWindow()
{
InitializeComponent();
dataGrid1.ItemsSource = idata;
dataGrid2.ItemsSource = dataGrid2Items;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
foreach (latlongobj item in dataGrid1.SelectedItems)
{
if( !dataGrid2Items.Contains( item ) )
dataGrid2Items.Add(item);
}
}
private ObservableCollection<latlongobj> idata = new ObservableCollection<latlongobj>
{
new latlongobj{ name = "n1", Lat = 1, Lon = 2 },
new latlongobj{ name = "n2", Lat = 2, Lon = 3 },
new latlongobj{ name = "n3", Lat = 4, Lon = 5 },
};

Categories