DataBinding 2 ComboBoxes wpf - binding

I need to build a form where I have 2 comboBoxes .
Select country and you get the cities of that country.
I m new to wpf so help me as I not sure what I am missing.
At the moment It doesnt even populate it.
Any help suggestions really appreaciated!
This is what I have done:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var window = new MainWindow();
var countryCitymodel = new CountryCityModel();
var repository = new CountryCityRepository();
var viewModel = new CountryCityViewModel(countryCitymodel, repository);
window.Show();
}
}
MainWindow xaml
<Window x:Class="WpfDatabinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:view="clr-namespace:WpfDatabinding.Views"
Title="MainWindow" Height="350" Width="525">
<Grid>
<view:CountryCityView />
</Grid>
</Window>
CountryCityView xaml
<UserControl x:Class="WpfDatabinding.Views.CountryCityView"
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"
mc:Ignorable="d"
d:DesignHeight="75" d:DesignWidth="300">
<Grid Height="64" Width="291">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="97"/>
<ColumnDefinition Width="13" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="Countries" Margin="-6,6,5,0" Grid.ColumnSpan="2" Height="33"></Label>
<Label Grid.Row="1" Content="Cities" Grid.ColumnSpan="2"></Label>
<ComboBox Name="cboCountries"
ItemsSource="{Binding Path=Countries}"
SelectedValuePath="Name"
DisplayMemberPath="{Binding Name}"
Grid.Column="2"
Margin="0,10"></ComboBox>
<ComboBox Name="cboCities"
Grid.Column="2"
Grid.Row="1"
ItemsSource="{Binding Path=Cities}" Height="20" Margin="0,0,0,1">
</ComboBox>
</Grid>
</UserControl>
CountryCityView
public partial class CountyrCityView:UserControl
{
public CountryCityView()
{
InitializeComponents();
}
public CountryCityView(CountryCityViewModel countryCityViewModel)
{
InitializeComponents();
DataContext=countryCityViewModel;
}
}
CountryCityViewModel
public class CountryCityViewModel : ViewModelBase
{
private readonly CountryCityModel _countryCityModel;
readonly CountryCityRepository _repository;
RelayCommand _getCountriesCommand;
private RelayCommand _getCitiesCommand;
public CountryCityViewModel(CountryCityModel countryCityModel, CountryCityRepository repository)
{
_countryCityModel = countryCityModel;
_repository = repository;
GetCountries.Execute(null);
}
public List<Country> Countries
{
get { return _countryCityModel.Countries; }
set
{
_countryCityModel.Countries = value;
OnPropertyChanged("Countries");
}
}
public List<City> Cities
{
get { return _countryCityModel.Cities; }
set
{
_countryCityModel.Cities = value;
OnPropertyChanged("Cities");
}
}
public Country SelectedCountry
{
get { return _countryCityModel.SelectedCountry; }
set
{
_countryCityModel.SelectedCountry = value;
OnPropertyChanged("SelectedCountry");
}
}
public City SelectedCity
{
get { return _countryCityModel.SelectedCity; }
set
{
_countryCityModel.SelectedCity = value;
OnPropertyChanged("SelectedCity");
}
}
public ICommand GetCountries
{
get
{
if (_getCountriesCommand == null)
{
_getCountriesCommand = new RelayCommand(param => GetCountryList(), param => CanGetCountries());
}
return _getCountriesCommand;
}
}
public ICommand GetCities
{
get
{
if (_getCitiesCommand == null)
{
_getCitiesCommand = new RelayCommand(param => GetCityList(), param => CanGetCities());
}
return _getCitiesCommand;
}
}
private List<Country> GetCountryList()
{
Countries = _repository.GetCountries();
return Countries;
}
private static bool CanGetCountries()
{
return true;
}
private List<City> GetCityList()
{
Cities = _repository.GetCities(SelectedCountry.Name);
return Cities;
}
private static bool CanGetCities()
{
return true;
}
}
Model
public class CountryCityModel
{
public List<Country> Countries { get; set; }
public List<City> Cities { get; set; }
public Country SelectedCountry{ get; set; }
public City SelectedCity { get; set; }
}
Types
public class City
{
public string Name { get; set; }
public string CountryName { get; set; }
}
public class Country
{
public string Name { get; set; }
}
Repository
public List<Country>GetCountries()
{
return new List<Country>
{
new Country{Name = "Italy"},
new Country{Name = "Germany"},
new Country{Name = "France"},
new Country{Name = "England"}
};
}
public List<City> GetCities(string countryName)
{
return Cities().Where(c => c.CountryName == countryName).ToList();
}
private static IEnumerable<City> Cities()
{
return new List<City>
{
new City { CountryName="Italy",Name = "Rome"},
new City {CountryName="France",Name = "Paris"},
new City{CountryName="Germany",Name ="Berlin"},
new City{CountryName="England",Name ="London"}
};
}
}

Are you setting the data context of the view to your ViewModel somewhere? I don't see that in the code listed above.
e.g.
var viewModel = new CountryCityViewModel(countryCitymodel, repository);
window.DataContext = viewModel;

Related

Binding between Data template and ListBox - Windows Phone

I'm having problems to do a binding in Windows Phone. Hope you can help me.
I have the following Data Template:
<DataTemplate>
<TextBox Name="txt1"/>
<TextBox Name="txt2"/>
</DataTemplate>
I have a ListBox that receives the following Class in the ItemsSource Property:
public class Product
{
private int _id;
public int Id
{
get { return _id; }
set { _id = value; }
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
Is there anyway to bind the Text property with the Object of the ListBoxItem like...
<TextBox Name="txt1" Text={Binding ElementName=ListBox, Path=SelectedItem.Product.Name}/>
I got a working example
xaml:
Here's the code
<Grid x:Name="gdTest" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,0,5,0" >
<ListBox Width="400" Margin="10" x:Name="lstDemo">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Id}" Margin="20" />
<TextBlock Text="{Binding Path=Name}" Margin="20"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using StackOverFlowTestApp.Resources;
using Microsoft.Phone.Tasks;
using Microsoft.Phone.UserData;
using Windows.UI;
using System.Windows.Media;
using System.IO;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework;
namespace StackOverFlowTestApp
{
public partial class MainPage : PhoneApplicationPage
{
private SoundEffect effect;
// Constructor
public MainPage()
{
InitializeComponent();
List<Product> liProd = new List<Product>();
for (int i = 0; i < 10; i++) {
liProd.Add(new Product()
{
Id = i,
Name = "Anobik" + i.ToString()
});
}
lstDemo.ItemsSource = liProd;
}
}
public class Product
{
private int _id;
public int Id
{
get { return _id; }
set { _id = value; }
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
}
if you require any more explanation then let me know.

XAML binding nested struct from ObservableCollection<T>

I am building a Windows Phone App, and I am trying to bind the ObservableCollection with nested struct without success.
MyViewModel.cs
public class MyViewModel : PropertyChangedBase
{
private Player _Player1;
public Player Player1
{
get { return _Player1; }
set
{
if (!value.Equals(_Player1))
{
_Player1 = value;
NotifyOfPropertyChange(() => Player1);
}
}
}
private Player _Player2;
public Player Player2
{
get { return _Player2; }
set
{
if (!value.Equals(_Player2))
{
_Player2 = value;
NotifyOfPropertyChange(() => Player2);
}
}
}
public struct Player
{
public string Name;
public bool IsWinner;
}
}
MyPageViewModel.cs
public class MyPageViewModel : Screen
{
public ObservableCollection<MyViewModel> Matches { get; private set; }
public MyPageViewModel()
{
this.Matches = new ObservableCollection<MyViewModel>();
LoadData();
}
public void LoadData()
{
// Matches
this.Matches.Add(new MyViewModel()
{
Player1 = new MyViewModel.Player
{ Name = "Jhonn", IsWinner = false },
Player2 = new MyViewModel.Player
{ Name = "Marrie", IsWinner = true }
});
}
}
MyPage.xaml
<ListBox Margin="0,0,-12,0" ItemsSource="{Binding Matches}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432">
<TextBlock Text="{Binding Player1.Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding Player2.Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I have no binding error, but no players names are showed. I always have a blank screen.
Your problem is here:
public struct Player
{
public string Name;
public bool IsWinner;
}
In order to be bound, Name needs to be a property. Make Player a class and expose Name as a property on the class and you'll be golden:
public class Player
{
public string Name {get; set;}
public bool IsWinner {get;set;}
}
You should be able to get away without implementing INotifyPropertyChanged, as long as you only set them one time. If they're going to change, go ahead and implement INPC.

Binding not happening in Silverlight 3 from class library

----------Class library file where i am calling WCF service-------------
public class AllEmployeeViewModel
{
// public ObservableCollection<Employee> Employees { get; set; }
public List<Employee> Employees { get; set; }
public void GetAllEmployees()
{
Proxy.EmployeeListCompleted += new EventHandler<EmployeeListCompletedEventArgs>(client_EmployeeListCompleted);
Proxy.EmployeeListAsync();
}
void client_EmployeeListCompleted(object sender, EmployeeListCompletedEventArgs e)
{
try
{
if (e.Error == null)
{
Employees = e.Result;
}
}
catch (Exception)
{
throw;
}
}
}
---------Mainpage.xaml-----------------
<UserControl.Resources>
<scr:AllEmployeeViewModel x:Key="empKey" />
</UserControl.Resources>
<Grid x:Name="MainGrid" Background="White" Width="400"
Height="407" DataContext="{Binding Source={StaticResource empKey}}">
<Grid x:Name="grdAllEmp" DataContext="{Binding Path=Employees}">
<data:DataGrid AutoGenerateColumns ="True" Height="274"
HorizontalAlignment="Left" Margin="8,8,0,0"
Name="dgEmployee" VerticalAlignment="Top" Width="385"
ItemsSource="{Binding}">
<data:DataGrid.Columns>
<data:DataGridTextColumn Header="FName" Binding="{Binding FName}">
</data:DataGridTextColumn>
<data:DataGridTextColumn Header="LName" Binding="{Binding LName}">
</data:DataGridTextColumn>
</data:DataGrid.Columns>
</data:DataGrid>
</Grid>
</Grid>
here i am sending data from class file as a datacontext to mainpage.xaml but binding is not happening, in my class file AllEmployeeViewMode i am able hit wcf and get data here
if (e.Error == null)
{
Employees = e.Result;
}
any help how to solve this would be great
thanks
prince
answer how i solved it
public class AllEmployeeViewModel
{
public ObservableCollection<Employee> Employees { get; set; }
WCF.EMPServiceClient Proxy;
public AllEmployeeViewModel()
{
try
{
Employees = new ObservableCollection<Employee>();
Proxy = new WCF.EMPServiceClient();
}
catch (Exception ex)
{
throw ex;
}
}
public ICommand GetEmployees
{
get
{
return new GetAllEmployeeCommand(this);
}
}
public void GetAllEmployees()
{
Proxy.EmployeeListCompleted += new EventHandler<EmployeeListCompletedEventArgs>(client_EmployeeListCompleted);
Proxy.EmployeeListAsync();
}
void client_EmployeeListCompleted(object sender, EmployeeListCompletedEventArgs e)
{
try
{
if (e.Error == null)
{
var emp = e.Result;
foreach (var item in emp)
Employees.Add(item);
}
}
catch (Exception)
{
throw;
}
}
}
then the values got binded in my xaml
You have not implement NotifyPropertyChanged for the Employees property. I can see a property above commented, which is an ObsevableCollection. If you use that, there should not be any problem with binding.
See this link for details.

Problem Binding via command.Can you help

New to wpf and through a learning curve.
I have a userControl with a Toolbar Save Button and a TextBox.
What I am trying to achieve is as follows
When I press the save Button in the toolbar I should record in the textbox that I am about to save and that I have saved the customer (CustomerView UserControl)
I seem to have 2 problems
1) that the SaveCommand is not hooked I thought I had hooked it
2) is not writing the action to the textbox.
Could you tell me where I am going wrong?
Thanks a lot!!!
MainWindow.xaml
<Window x:Class="MyCompany.CustomerStore.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:view="clr-namespace:MyCompany.CustomerStore.Views"
Title="MainWindow" Height="350" Width="525">
<Grid>
<view:CustomerView></view:CustomerView>
</Grid>
CustomerView.xaml
<UserControl x:Class="MyCompany.CustomerStore.Views.CustomerView"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<DockPanel LastChildFill="True">
<ToolBar DockPanel.Dock="Top">
<Button Command="{Binding Path=SaveCommand}">Save</Button>
</ToolBar>
<TextBox Name="txtPrintAction" Text="{Binding CustomerLog, Mode=TwoWay}"></TextBox>
</DockPanel>
</Grid>
CustomerModel.cs
public class CustomerModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string CustomerLog { get; set; }
}
CustomerViewModel.cs
public class CustomerViewModel:WorkspaceViewModel,ICustomerViewModel
{
readonly CustomerModel _customerModel;
RelayCommand _saveCommand;
public CustomerViewModel(CustomerModel customer)
{
_customerModel = customer;
}
public string FirstName
{
get { return _customerModel.FirstName; }
set
{
_customerModel.FirstName = value;
base.OnPropertyChanged("FirstName");
}
}
public string LastName
{
get { return _customerModel.LastName; }
set
{
_customerModel.LastName = value;
base.OnPropertyChanged("LastName");
}
}
public string CustomerLog
{
get { return _customerModel.CustomerLog; }
set
{
_customerModel.CustomerLog = value;
base.OnPropertyChanged("CustomerLog");
}
}
public ICommand SaveCommand
{
get
{
if (_saveCommand == null)
{
_saveCommand = new RelayCommand(param => Save(), param => CanSave);
}
return _saveCommand;
}
}
private void Save()
{
AppendToLog("I am about to save");
//Pretend we have saved the customer
AppendToLog("CustomerSaved");
}
internal void AppendToLog(string text)
{
_customerModel.CustomerLog += text + Environment.NewLine; ;
OnPropertyChanged("CustomerLog");
}
static bool CanSave
{
get
{
return true;
}
}
Where do you declare a relationship between the view
x:Class="MyCompany.CustomerStore.Views.CustomerView
and the model class CustomerViewModel?
I don't see that anywhere.
I think you need to set the DataContext of the View to the Model.

WPF - Binding to CheckBox not working in a HierarchicalDataTemplate

In a WPF treeview I am trying to automatically check the children if the parent node is being checked. I am using a view model for that and a bindable object for the nodes, however all my attempts failed. Here is the code (C# + XAML). Any ideas would be greatly appreciated
<Window x:Class="TestCheckBoxBinding.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestCheckBoxBinding"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True"/>
</Style>
<HierarchicalDataTemplate DataType="{x:Type local:TestCategory}" ItemsSource="{Binding Tests, Mode=OneTime}">
<Label Content="{Binding Name}"></Label>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:Test}" ItemsSource="{Binding Children, Mode=OneTime}">
<StackPanel Orientation="Horizontal">
<CheckBox VerticalAlignment="Center" IsChecked="{Binding IsChecked, Mode=TwoWay}"></CheckBox>
<Label Content="{Binding Name}"></Label>
</StackPanel>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid>
<TreeView ItemsSource="{Binding Categories, Mode=OneTime}"></TreeView>
</Grid>
public class TestsViewModel
{
public static void PopulateList(TestsViewModel vm)
{
TestCategory cat1 = new TestCategory() { Id = 1, Name = "First category" };
Test t1 = new Test() { Name = "Test1" };
Test t2 = new Test() { Name = "Test2" };
Test t3 = new Test() { Name = "Test3" };
t1.AddChild(t2);
t1.AddChild(t3);
Test t4 = new Test() { Name = "Test4" };
cat1.AddTest(t1);
cat1.AddTest(t4);
vm.AddTestCategory(cat1);
TestCategory cat2 = new TestCategory() { Id = 2, Name = "Second category" };
Test t5 = new Test() { Name = "Test1" };
Test t6 = new Test() { Name = "Test2" };
Test t7 = new Test() { Name = "Test3" };
t6.AddChild(t7);
Test t8 = new Test() { Name = "Test4" };
cat2.AddTest(t5);
cat2.AddTest(t6);
cat2.AddTest(t8);
vm.AddTestCategory(cat2);
}
private readonly IEnumerable<TestCategory> categories = new List<TestCategory>();
public IEnumerable<TestCategory> Categories { get { return categories; } }
public void AddTestCategory(TestCategory testCategory)
{
((IList<TestCategory>)categories).Add(testCategory);
}
}
public class TestCategory
{
public int Id { get; set; }
public string Name { get; set; }
private readonly IEnumerable<Test> tests = new List<Test>();
public IEnumerable<Test> Tests { get { return tests; } }
public void AddTest(Test t)
{
((IList<Test>)tests).Add(t);
}
}
public class Test : INotifyPropertyChanged
{
private string name;
public string Name
{
set
{
if (name != value)
{
name = value;
this.OnPropertyChanged("Name");
}
}
get { return name; }
}
public bool? isChecked = false;
public bool? IsChecked
{
get { return isChecked; }
set
{
if (isChecked != value)
{
isChecked = value;
if (children.Count() > 0)
{
foreach (var test in children)
{
test.isChecked = value;
test.Name += ".";
}
}
this.OnPropertyChanged("IsChecked");
}
}
}
public void AddChild(Test test)
{
((IList<Test>)children).Add(test);
}
private readonly IEnumerable<Test> children = new List<Test>();
public IEnumerable<Test> Children
{
get { return children; }
}
#region INotifyPropertyChanged Members
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string propName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
Oups, child checkboxes are not being checked because I wasn't setting their IsChecked property. I was setting the isChecked field, which bypasses the property setter and prevents PropertyChanged from being raised.

Resources