Filling WPF Combobox with SQL Column - c#

Going off of this thread: Attach a SQL database to ComboBox.ItemSource (WPF)
I am still confused on how to execute. Below is my code for my GUI. I am new to C# and am unsure how to manipulate the combo box.
I am trying to take data from a SQL query and fill the values of a combobox.
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 List
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var instance = new SQLInformation();
instance.fillComboBox("Data Source=server Initial Catalog=db; User id=user; Password=pass;", System.Windows.Controls.ComboBox. , "select distinct [location] from [dbo].[locations]", null, "[location]");
}
}
}
SQL Information code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.SqlClient;
using System.Data;
using System.Collections.Specialized;
using System.Configuration;
namespace List
{
public class SQLInformation
{
public bool fillComboBox(string connectionString, System.Windows.Controls.ComboBox combobox, string query, string defaultValue, string itemText)
{
SqlCommand sqlcmd = new SqlCommand();
SqlDataAdapter sqladp = new SqlDataAdapter();
DataSet ds = new DataSet();
try
{
using (SqlConnection _sqlconTeam = new SqlConnection(ConfigurationManager.ConnectionStrings[connectionString].ConnectionString))
{
sqlcmd.Connection = _sqlconTeam;
sqlcmd.CommandType = CommandType.Text;
sqlcmd.CommandText = query;
_sqlconTeam.Open();
sqladp.SelectCommand = sqlcmd;
sqladp.Fill(ds, "defaultTable");
DataRow nRow = ds.Tables["defaultTable"].NewRow();
nRow[itemText] = defaultValue;
ds.Tables["defaultTable"].Rows.InsertAt(nRow, 0);
combobox.DataContext = ds.Tables["defaultTable"].DefaultView;
combobox.DisplayMemberPath = ds.Tables["defaultTable"].Columns[0].ToString();
combobox.SelectedValuePath = ds.Tables["defaultTable"].Columns[1].ToString();
}
return true;
}
catch (Exception expmsg)
{
return false;
}
finally
{
sqladp.Dispose();
sqlcmd.Dispose();
}
}
}
}
Here is my XAML code:
<Window x:Class="List.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="FirstWindow" Height="390" Width="683">
<Window.Background>
<LinearGradientBrush StartPoint='0,0' EndPoint='0,1'>
<LinearGradientBrush.GradientStops>
<GradientStop Color='#FFC1C1C1' Offset="0.99" />
<GradientStop Color='White' />
<GradientStop Color="#FFE4E4E4" Offset="0.397"/>
<GradientStop Color="#FFD1D1D1" Offset="0.777"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Window.Background>
<Grid>
<Grid Height="360" VerticalAlignment="Top">
<Image HorizontalAlignment="Left" Height="50" Margin="119,10,0,0" VerticalAlignment="Top" Width="270" Source=""/>
<Image HorizontalAlignment="Left" Height="23" Margin="153,50,0,0" VerticalAlignment="Top" Width="209" Source=""/>
<ComboBox x:Name="LocationComboBox" HorizontalAlignment="Left" Margin="153,122,0,0" VerticalAlignment="Top" Width="73" SelectedIndex="0">
</ComboBox>
</Grid>
</Grid>
</Window>

You are approaching this the wrong way. WPF was designed to work well using data binding and the MVVM methodology (Model->View->ViewModel). You should do some reading up on MVVM, as it is very powerful and will help you write better WPF apps. Your Window XAML file should just have layout code, and each property that you want bound to some data should use a {Binding} expression in the XAML.
For example, if you want to bind this ComboBox to a list of locations, you can use this XAML:
<ComboBox ItemsSource="{Binding Locations}" />
And then in your ViewModel class, you can expose a property called Locations that returns a list of the locations from the database, like this:
First create a ViewModel class and implement the INotifyPropertyChanged interface:
public class MainViewModel : INotifyPropertyChanged
Then inside the class you'll add a public Property called Locations:
private ObservableCollection<string> _locations;
public ObservableCollection<string> Locations
{
get { return _locations; }
set
{
_locations = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Locations"));
}
}
Notice how I've implemented the INotifyPropertyChanged interface on my ViewModel class. This interface is used by WPF to update the UI whenever a property on the underlying model changes. You can see where I am invoking the PropertyChanged event when my Locations list changes. This tells the UI that it should update any UI controls that are bound to Locations.
In the constructor of your MainWindow.xaml.cs file, you should set the DataContext to a new instance of this ViewModel:
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
And this is what my final MainViewModel class looks like. You can replace my code with some real database code to populate the Locations list:
public class MainViewModel : INotifyPropertyChanged
{
private ObservableCollection<string> _locations;
public ObservableCollection<string> Locations
{
get { return _locations; }
set
{
_locations = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Locations"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public MainViewModel()
{
// Load our locations from the database here
// You can instead populate yours from SQL
Locations = new ObservableCollection<string>();
Locations.Add("Location 1");
Locations.Add("Location 2");
Locations.Add("Location 3");
Locations.Add("Location 4");
// Now your combobox should be populated
}
}

Related

Datagrid stays Empty but ObservableCollection has values

Currently i am trying to learn WPF, but i have hit a brickwall with my current Problem, after many hours googling and trying to fix it on my own. I am trying to display the Model Province. I have found multiple similar Problems but i couldn't figure it out on my own. After having checked the Output there was no mention of any error. Currently the Window shows just the empty Model but no data even though the Observable Collection gets updated. So before i completely destroy my interest in WPF i am asking for help.
MyView
<Window x:Class="isnuaatest.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:isnuaatest"
xmlns:local1="clr-namespace:isnuaatest.Models"
xmlns:local2="clr-namespace:isnuaatest.ViewModel"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local2:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Grid>
<DataGrid ItemsSource="{Binding Provinces, UpdateSourceTrigger=PropertyChanged}">
</DataGrid>
</Grid>
<StackPanel Width="200" Margin="50">
<Button x:Name="OpenSaveFile" Click="OpenSaveFile_Click">OpenSaveFile</Button>
</StackPanel>
</Grid>
My View Model
using isnuaatest.Helper;
using isnuaatest.Models;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Input;
namespace isnuaatest.ViewModel
{
public class MainWindowViewModel : INotifyPropertyChanged
{
public ObservableCollection<Province> _province;
public ObservableCollection<Province> Provinces
{
get { return this._province; }
set
{
_province = value;
}
}
public MainWindowViewModel() : base()
{
this.Provinces = new ObservableCollection<Province>();
}
private string _savegamePath;
public string SavegamePath
{
get { return _savegamePath; }
set { _savegamePath = value; OnPropertyChanged("SavegamePath"); GetProvinces(_savegamePath);}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var savegamefile = this.PropertyChanged;
if (savegamefile != null)
savegamefile(this, new PropertyChangedEventArgs(propertyName));
}
public event EventHandler OnItemChanged;
public void GetProvinces(string path)
{
Reader reader = new Reader();
if (_savegamePath != null)
{
FileStream fs = File.OpenRead(path);
List<Province> listofProvinces = reader.ReadTextString(fs);
foreach (Province province in listofProvinces)
{
Provinces.Add(new Province()
{
Aristocrats = province.Aristocrats,
Artisans = province.Artisans
});
}
}
}
}
}
Code Behind
using isnuaatest.Helper;
using isnuaatest.Models;
using isnuaatest.ViewModel;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
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 isnuaatest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindowViewModel _vm = new MainWindowViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
private void OpenSaveFile_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog fileDialog = new OpenFileDialog();
fileDialog.Multiselect = false;
dynamic result = fileDialog.ShowDialog();
if (result == true)
{
_vm.SavegamePath = fileDialog.FileName;
}
}
}
}
My thinking is that maybe the Data Context wont update, because the data is in the Observable Collection. If this is true how can i update the Data Context, i already tried adding it in xaml to no avail.
Thanks
You actually create 3 different MainWindowViewModel objects - one in xaml and two in code behind. You can get rid of one in xaml, once in MainWindow constructor you set DataContext xaml-one is overridden.
But two objects in code-behind cause your problem - you load file into _vm object, but it's not the one that is held in DataContext.
To fix your problem use _vm for DataContext and not the new object:
public MainWindowViewModel _vm = new MainWindowViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = _vm;
}
Change your Provinces:
public ObservableCollection<Province> Provinces
{
get { return this._province; }
set
{
_province = value;
OnPropertyChanged("Provinces");
}
}

why does the datacontext in my WPF project function correctly from code behind but not from xaml? [duplicate]

This question already has answers here:
WPF Binding Image Source
(2 answers)
Closed 5 years ago.
I have been working on a small sample Wpf Mvvm project for experimenting with INotifyPropertyChanged interface. The project actually works correctly, but the problem that I am having is that the project only works correctly if I set the DataContext in the code behind of MainWindow.xaml. If I try to set the DataContext in the xaml markup then some of the features of the project don't work. The UI contains a textblock, textbox (for entering text to display in the textblock OnPropertyChanged) and submit button (which really does nothing except provide a place to lose focus from textbox) and 3 other buttons (color buttons) for changing the background color of the UI. The default color of the UI is orange -- until the color is changed by clicking any of the color buttons
There are 3 viewModels, PersonViewModel (which the textbox binds to), BackgroundViewModel (for the color buttons) and a MainViewModel which combines the two other viewModels. The viewModels reside in the viewModels folder of the project. There is also an ObservableObject class (ViewModelBase class basically) which implement INotifyPropertyChanged interface and gets inherited by PersonViewModel and BackgroundViewModel. ObservableObject.cs resides in the root folder of the project.
The Project isn't pure Mvvm. The color buttons use a click event in the code behind of MainWindow.xaml. If I set the DataContext in the Code behind of MainWindow.xaml everything works correctly. If I set the DataContext in the xaml markup -- the textbox/textblock features works but the color buttons won't change the background color of the UI. When I step through the code it runs through all the code correctly but the UI background colors don't change. I am guessing it is a binding thing.
The sample project can be downloaded here
The code is below. How can I make this project function correctly if I set the DataContext in the xaml markup? I tried the following binding on the Grid which WILL set the default orange color for the UI, but the color buttons don't work:
<Grid Background="{Binding Background.Color}" DataContext="{StaticResource bc}">
--MainWindow.xaml
<Window x:Class="NotifyChangeExample.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:NotifyChangeExample"
xmlns:VM="clr-namespace:NotifyChangeExample.ViewModels"
mc:Ignorable="d"
Title="MainWindow" Height="550" Width="525">
<!--<Window.DataContext>
<VM:MainViewModel />
</Window.DataContext>-->
<Window.Resources>
<VM:MainViewModel x:Key="bc" />
</Window.Resources>
<Grid Background="{Binding Background.Color}" DataContext="{StaticResource bc}">
<!--<Grid Background="{Binding Background.Color}">-->
<DockPanel LastChildFill="False" Margin="0,82,0,0">
<StackPanel Width="150" DockPanel.Dock="Top">
<TextBlock Text="{Binding Person.Name, StringFormat=Welcome (0)}" />
<TextBox Text="{Binding Person.Name, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" />
<Button>Submit</Button>
</StackPanel>
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" DockPanel.Dock="Bottom" >
<Button Click="Red_Clicked">Red Background</Button>
<Button Click="Blue_Clicked">Blue Background</Button>
<Button Click="Yellow_Clicked">Yellow Background</Button>
</StackPanel>
</DockPanel>
</Grid>
</Window>
--MainWindow.xaml.cs
using NotifyChangeExample.ViewModels;
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 NotifyChangeExample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
MainViewModel _main = new MainViewModel();
public MainWindow()
{
InitializeComponent();
//DataContext = _main;
}
private void Red_Clicked(object sender, RoutedEventArgs e)
{
_main.SetBackground(Brushes.Red);
}
private void Blue_Clicked(object sender, RoutedEventArgs e)
{
_main.SetBackground(Brushes.Blue);
}
private void Yellow_Clicked(object sender, RoutedEventArgs e)
{
_main.SetBackground(Brushes.Yellow);
}
}
}
--ObservableObject.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NotifyChangeExample
{
public class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
}
--PersonViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NotifyChangeExample.ViewModels
{
public class PersonViewModel : ObservableObject
{
private string _name;
public string Name
{
get
{
if (string.IsNullOrEmpty(_name))
return "Unknown";
return _name;
}
set
{
_name = value;
OnPropertyChanged("Name");
}
}
}
}
--BackgroundViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
namespace NotifyChangeExample.ViewModels
{
public class BackgroundViewModel : ObservableObject
{
private Brush _color;
public Brush Color
{
get
{
if (_color == null)
return Brushes.Orange;
return _color;
}
set
{
_color = value;
OnPropertyChanged("Color");
}
}
}
}
--MainViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
namespace NotifyChangeExample.ViewModels
{
public class MainViewModel
{
public PersonViewModel Person { get; private set; }
public BackgroundViewModel Background { get; private set; }
public MainViewModel()
{
Person = new PersonViewModel();
Background = new BackgroundViewModel();
}
public void SetBackground(Brush brushColor)
{
Background.Color = brushColor;
}
}
}
Your code behind is using the _main object so if you want to set the DataContext in the XAML, you just need to set _main using the DataContext.
So in the XAML you would have
<Window.DataContext>
<VM:MainViewModel />
</Window.DataContext>
and in your code behind you would set _main by casting the DataContext to a MainViewModel
MainViewModel _main;
public MainWindow()
{
InitializeComponent();
_main = (MainViewModel) DataContext;
}
Alternatively, remove the DataContext from XAML, and use this MainWindow constructor:
private readonly MainViewModel _main = new MainViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = _main;
}
When you are binding your ViewModel from XAML it can't work, because in your code-behind you are setting the colors to your local ViewModel "_main". But _main is not bound to the View, bc is.

In WPF Can I have a button event in the MainWindow.xaml reference code in my own class? [duplicate]

On a button's click, i want it to execute an event handler method that is another class apart from the window class.
I believe creating a ObjectDataProvider object which is binded to the event handler method in the other class, then binding said object to the Click event would do the trick, but it didn't.
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.Shapes;
using System.Windows.Media.Animation;
using System.Windows.Threading;
using System.Data.SqlClient;
namespace LoginNS
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class LoginWindow : Window
{
public LoginWindow()
{
InitializeComponent();
}
}
public class SQLServerClass
{
public void ConnectSQLServer(object sender, RoutedEventArgs e)
{
try
{
SqlConnection conn = new SqlConnection("Data Source=tcp:172.16.1.71;Initial Catalog=Sample;User ID=sa;Password=hbkrko");
conn.Open();
MessageBox.Show("success");
}
catch
{
MessageBox.Show("db error");
}
}
}
}
Here is the resource and how i'm using it which is incorrect because i get an error message:
<ObjectDataProvider x:Key="loginFunction" ObjectType="{x:Type local:SQLServerClass}" MethodName="ConnectSQLServer"/>
<Grid DataContext="{Binding Path=LoginNS}" Width="400" Height="200">
<Button x:Name="LoginButton" Style="{StaticResource LoginButton}" Click="{Binding Source={StaticResource loginFunction}}"/>
</Grid>
Immediate run-time error:
Additional information: 'Provide value on 'System.Windows.Data.Binding' threw an exception.' Line number '24' and line position '75'.
ObjectDataProvider is used to create object instances that can be used as binding source. In your case ConnectSQLServer method does not return any object that can be used for binding.
The best option for your scenario is to use RelayCommand. You can read about how to achieve this at http://www.codeproject.com/Articles/126249/MVVM-Pattern-in-WPF-A-Simple-Tutorial-for-Absolute
In your case, with RelayCommand your SQLServerClass will be something like this
public class SQLServerClass
{
public SQLServerClass()
{
LoginCommand = new RelayCommand<object>(LoginCommandExecute, LoginCommandCanExecute);
}
public void ConnectSQLServer(object sender, RoutedEventArgs e)
{
try
{
SqlConnection conn = new SqlConnection("Data Source=tcp:172.16.1.71;Initial Catalog=Sample;User ID=sa;Password=hbkrko");
conn.Open();
MessageBox.Show("success");
}
catch
{
MessageBox.Show("db error");
}
}
public ICommand LoginCommand { get; set; }
private void LoginCommandExecute(object arg)
{
ConnectSQLServer(this, new RoutedEventArgs());
}
private bool LoginCommandCanExecute(object arg)
{
return true;
}
}
And your XAML
<Window.Resources>
<ObjectDataProvider x:Key="loginFunction" ObjectType="{x:Type local:SQLServerClass}"/>
</Window.Resources>
<Grid>
<Grid Width="400" Height="200">
<Button x:Name="LoginButton" Command="{Binding Path=LoginCommand, Source={StaticResource loginFunction}}"/>
</Grid>
</Grid>
Note that you can use the MvvmLight library. It already contains an implementation of the RelayCommand class and other useful classes for WPF MVVM application.
Why can't you use this:
InitializeComponent();
sqlServerInstance = new SQLServerClass();
LoginButton.Click += MainConnectSQLServer()
And
private void MainConnectSQLServer(object sender, RoutedEventArgs e)
{
sqlServerInstance.ConnectSQLServer(sender, e);
}

adding new row dynamic to datagrid

I am new with WPF and I am trying to add a new to the data grid I created.
The rows I am adding should be added dynamically however I can't see the values of the data in in the data grid.
Here is the xaml:
<Window x:Class="ProtocolAnalyzer.createByProtocol"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="createByProtocol" Height="506" Width="384">
<Grid Margin="0,0,2,4">
<DataGrid x:Name="dataGridTable" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="452" Width="245">
<DataGrid.Columns>
<DataGridTextColumn Header="Field"/>
<DataGridTextColumn Header="Value"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
Here is my code:
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 ProtocolAnalyzer
{
/// <summary>
/// Interaction logic for createByProtocol.xaml
/// </summary>
public partial class createByProtocol : Window
{
private ProtocolData.ProtocolData.Protocols _runningProtocol;
public class Data
{
public string Name { get; set; }
public string Value { get; set; }
}
public createByProtocol(ProtocolData.ProtocolData.Protocols protocol)
{
InitializeComponent();
_runningProtocol = protocol;
buildTable();
}
private void buildTable()
{
switch (_runningProtocol)
{
case ProtocolData.ProtocolData.Protocols.ZBM:
dataGridTable.Items.Add("");
dataGridTable.Items[0] = "FFF";
break;
}
}
}
}
EDIT: some general information for "dynamic controls" in wpf/mvvm
if you go the MVVM style you do something like this.
viewmodel
//your data
public ObservableCollection<Customer> MySource {get;set;}
//Command to add a new row
public ICommand AddNewCustomerCommand {get{return _lazyAddCommand.Value;}}
private readonly Lazy<DelegateCommand> _lazyAddCommand;
//ctor
public MyViewmodel()
{
MySource = new ObservableCollection<Customer>();
_lazyAddCommand= new Lazy<DelegateCommand>(() => new DelegateCommand(AddNewCustomerCommandExecute, CanAddNewCustomerCommandExecute));
}
private bool CanAddNewCustomerCommandExecute()
{
return true;//your Conditions goes here
}
private void AddNewCustomerCommandExecute()
{
if (!CanAddNewCustomerCommandExecute())
return;
//Add new Customer
MySource.Add(new Customer());
}
view: use Binding to set the ItemsSource for your Datagrid
<DataGrid ItemsSource="{Binding MySource}">
<DataGrid.Columns>
<DataGridTextColumn Header="Field"/>
<DataGridTextColumn Header="Value"/>
</DataGrid.Columns>
</DataGrid>
thats all. the new row will display as far as your command is invoked through a button or something else
if you have data in "DataTable" that you are trying to assign to datagrid then you can use datagrid.Datasource porperty
If you have a list or an array..
then just use foreach loop and under that loop add you rows.

List<string> is not updated back to ListBox's ItemsSource?

I'm new to WPF. I have a List<string> as a source for my ListBox's ItemsSource. Initially, the ListBox shows all the Items in my List<string> OK. However, after trying adding some string to my List<string>, the ListBox doesn't update the changes. I'm using Binding to bind the data (behind) with the ListBox (view), here is my code:
//Code behind
public MainWindow: Window {
public MainWindow(){
InitializeComponent();
Items = new List<string>(){"1","2","3"};//after loaded, all these values are displayed OK in my ListBox.
DataContext = this;
//Try clicking on a button to add new value
button1.Click += (s,e) => {
Items.Add("4");//But my ListBox stays the same without any update/changes.
};
}
public List<string> Items {get;set;}
}
//XAML
<ListBox ItemsSource={Binding Items}/>
Could you please point out what I'm doing wrong here and give me a solution? Thank you very much in advance.
If you had read the documentation of ItemsSource you would already know what is wrong.
[...]
This example shows how to create and bind to a collection that derives from the ObservableCollection<T> class, which is a collection class that provides notifications when items get added or removed.
you should try ObservableCollection instead because it's
Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.
<Window x:Class="WpfApplication3.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 Click="Button_Click" Content="Button" HorizontalAlignment="Left" Margin="441,289,0,0" VerticalAlignment="Top" Width="75"/>
<ListBox HorizontalAlignment="Left" ItemsSource="{Binding MyList,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Name="lstbox" Height="296" Margin="21,23,0,0" VerticalAlignment="Top" Width="209"/>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
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 WpfApplication3
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ObservableCollection<string> _myList = new ObservableCollection<string>(new List<string>(){"1","2","3"});
int i = 3;
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MyList.Add(i++.ToString());
}
public ObservableCollection<string> MyList
{
get { return _myList; }
set { _myList = value; }
}
}
}

Categories

Resources