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
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.
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.
----------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.
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.
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.