SearchBar and Xamarin.Form - xamarin.forms

Am working on a XF project which has a SearchBar. The XAML Declaration looks like following.
<SearchBar Placeholder="Result" Text="{Binding SearchedCustomer,Mode=TwoWay}"
SearchCommand="{Binding SearchCustomerCommand}"></SearchBar>
At ViewModel, I have following declared
private string _SearchedCustomer;
public string SearchedCustomer
{
get { return _SearchedCustomer; }
set { SetProperty(ref _SearchedCustomer, value); }
}
public DelegateCommand SearchCustomerCommand { get; set; }
private ObservableCollection<CustomerModel> _CustomerList;
public ObservableCollection<CustomerModel> CustomerList
{
get
{
if (_CustomerList == null)
FillCustomerDetails();
return _CustomerList;
}
set { SetProperty(ref _CustomerList, value); }
}
private void ExecuteSearchCustomerCommand()
{
var tempRecords = _CustomerList.Where(c => c.ReferenceText.Contains(SearchedCustomer));
CustomerList.Clear();
foreach (var item in tempRecords)
{
CustomerList.Add(item);
}
}
I also have the SearchCustomerCommand created in the Constructor as following
SearchCustomerCommand = new DelegateCommand(ExecuteSearchCustomerCommand).ObservesProperty(()=> SearchedCustomer);
When I type in the SearchBar, the SearchedCustomer Fields gets changed, however, the Command SearchCustomerCommand is not executed.
Could someone help me in identifying what I am doing wrong here ?

Related

Xamarin application not navigating back

Problem
This is the process:
Select a category from list.
Load Tasks page.
Tasks are loaded depending on the categoryId selected from the previous page. (Navigate back to Category page is possible ✔️)
Select a Task from from list.
Load Task Page.
Task details are loaded on the page. (Navigate back to Tasks page is not possible ❌)
Video
Question
I do not understand why I cannot navigate back a page. How can I fix this?
Code
CategoriesViewModel
public class CategoriesViewModel : BaseViewModel
{
public ObservableCollection<CategoryModel> Categories { get; } = new ObservableCollection<CategoryModel>();
public Command LoadCategoriesCommand { get; }
public Command<CategoryModel> SelectedCategory { get; }
public CategoriesViewModel()
{
Title = "Categories";
LoadCategoriesCommand = new Command(async () => await LoadCategories());
SelectedCategory = new Command<CategoryModel>(OnSelectedCategory);
}
private async Task LoadCategories()
{
IsBusy = true;
try
{
Categories.Clear();
var categories = await DatabaseService.GetCategoriesAsync();
foreach (var category in categories)
{
this.Categories.Add(category);
}
}
catch (Exception)
{
throw;
}
finally
{
IsBusy = false;
}
}
private async void OnSelectedCategory(CategoryModel category)
{
if (category == null)
return;
await Shell.Current.GoToAsync($"{nameof(TasksPage)}?{nameof(TasksViewModel.CategoryId)}={category.CategoryId}");
}
public void OnAppearing()
{
IsBusy = true;
}
}
TasksViewModel
[QueryProperty(nameof(CategoryId), nameof(CategoryId))]
public class TasksViewModel : BaseViewModel
{
public ObservableCollection<TaskModel> Tasks { get; } = new ObservableCollection<TaskModel>();
private int categoryId;
public int CategoryId
{
get { return categoryId; }
set
{
categoryId = value;
}
}
public Command LoadTasksCommand { get; set; }
public Command<TaskModel> SelectedTask { get; set; }
public TasksViewModel()
{
Title = "Tasks";
LoadTasksCommand = new Command(async () => await LoadTasks());
SelectedTask = new Command<TaskModel>(OnSelectedTask);
}
private async Task LoadTasks()
{
IsBusy = true;
try
{
this.Tasks.Clear();
var tasks = await DatabaseService.GetTasksAsync(CategoryId);
foreach (var task in tasks)
{
this.Tasks.Add(task);
}
}
catch (Exception)
{
throw;
}
finally
{
IsBusy = false;
}
}
private async void OnSelectedTask(TaskModel task)
{
if (task == null)
return;
await Shell.Current.GoToAsync($"{nameof(TaskPage)}?{nameof(TaskViewModel.TaskId)}={task.TaskId}");
}
public void OnAppearing()
{
IsBusy = true;
}
}
TaskViewModel
[QueryProperty(nameof(TaskId), nameof(TaskId))]
public class TaskViewModel : BaseViewModel
{
private int taskId;
public int TaskId
{
get { return taskId; }
set
{
taskId = value;
}
}
private string taskTitle;
public string TaskTitle
{
get { return taskTitle; }
set
{
taskTitle = value;
OnPropertyChanged(nameof(TaskTitle));
}
}
private string description;
public string Description
{
get { return description; }
set
{
description = value;
OnPropertyChanged(nameof(Description));
}
}
public Command LoadTaskCommand { get; }
public TaskViewModel()
{
LoadTaskCommand = new Command(async () => await LoadTask());
}
private async Task LoadTask()
{
IsBusy = true;
try
{
var task = await DatabaseService.GetTaskAsync(TaskId);
this.TaskTitle = task.Title;
this.Description = task.Description;
}
catch (Exception)
{
throw;
}
finally
{
IsBusy = false;
}
}
public void OnAppearing()
{
IsBusy = true;
}
}
Update 1
I tried replacing this line of code in TasksViewModel:
await Shell.Current.GoToAsync($"{nameof(TaskPage)}?{nameof(TaskViewModel.TaskId)}={task.TaskId}");
to this:
await Shell.Current.Navigation.PushAsync(new AboutPage());
Also, the same outcome.
Update 2
As per requested comment, here is the TaskPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:vm="clr-namespace:SomeProject.ViewModels"
x:Class="SomeProject.Views.Task.TaskPage"
Title="{Binding TaskTitle}">
<ContentPage.Content>
<RefreshView x:DataType="vm:TaskViewModel"
Command="{Binding LoadTaskCommand}"
IsRefreshing="{Binding IsBusy, Mode=TwoWay}">
<StackLayout>
<Label Text="{Binding Description}" />
</StackLayout>
</RefreshView>
</ContentPage.Content>
</ContentPage>
and TaskPage.xaml.cs:
public partial class TaskPage : ContentPage
{
TaskViewModel _viewModel;
public TaskPage()
{
InitializeComponent();
BindingContext = _viewModel = new TaskViewModel();
}
protected override void OnAppearing()
{
base.OnAppearing();
_viewModel.OnAppearing();
}
}
Update 3
As per requested comment, here is the routes:
public AppShell()
{
InitializeComponent();
Routing.RegisterRoute(nameof(CategoriesView), typeof(CategoriesView));
Routing.RegisterRoute(nameof(TasksPage), typeof(TasksPage));
Routing.RegisterRoute(nameof(TaskPage), typeof(TaskPage));
}
Check your registers route.
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/navigation#register-page-routes
In the Shell subclass constructor, or any other location that runs
before a route is invoked, additional routes can be explicitly
registered for any pages that aren't represented in the Shell visual
hierarchy
I had CategoryPage registered in AppShell.xaml.cs and also AppShell.xaml like so:
<ShellContent Route="CategoryPage" ContentTemplate="{DataTemplate local:CategoryPage}" />
Only can register one route in one or the other.

Sending data from Main to Detail and Updating Object in MainViewMode

I have the following recyclerview where it contains list of TestViewModel objects. In this object I have age, gender and name properties. I am trying to achieve when user click on a list item, it takes user to detail view where user could able to update and click on the save button, then it updates the selected item properties.
Issue:
The following piece of code in MainViewModel where I receive the message from DetailViewModel works when user enter values in the detail and updating each property,
private void OnMessageReceived(TestMessage obj)
{
_selectedItem.Age = obj.messageTest.Age;
_selectedItem.Name = obj.messageTest.Name;
_selectedItem.Gender = obj.messageTest.Gender;
}
but the following piece of code does not work where I am trying to update the object by itself directly.
private void OnMessageReceived(TestMessage obj)
{
_selectedItem= obj.messageTest;
RaisePropertyChanged(() => SelectedItem);
}
Code Implementation is as follows:
<MvxRecyclerView
android:id="#+id/TestRecyclerView"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
local:MvxBind="ItemsSource TestsViews; ; ItemClick ItemSelected" />
MainViewModel
public MainViewModel SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
ShowViewModel<DetailViewModel>(
new DetailViewModel.Parameter
{
Age = _selectedItem.Age,
Name = _selectedItem.Name,
Gender = _selectedItem.Gender,
});
RaisePropertyChanged(() => SelectedItem);
}
}
public virtual ICommand ItemSelected
{
get
{
return new MvxCommand<TestViewModel>(item =>
{
SelectedItem = item;
});
}
}
private void OnMessageReceived(TestMessage obj)
{
_selectedItem.Age= obj.messageTest.Age;
_selectedItem.Name= obj.messageTest.Name;
_selectedItem.Gender= obj.messageTest.Gender;
}
TestMessage
public class TestMessage : MvxMessage
{
public MainModel messageTest { get; set; }
public TestMessage(object sender, MainModel editTest) : base(sender)
{
messageTest = editTest;
}
}
DetailViewModel
public TestViewModel EditTest
{
get { return _editTest; }
set
{
_editTest = value;
RaisePropertyChanged(() => EditTest);
}
}
public DetailViewModel(IMvxMessenger messenger)
{
_messenger = messenger;
}
public void Save()
{
UpdateValues();
}
public void UpdateValues()
{
var message = new TestMessage(this, _editTest);
_messenger.Publish(message, typeof(TestMessage));
}
public void Init(Parameter param)
{
_editTest = new TestViewModel();
_editTest.Age = param.Age;
_editTest.Name = param.Name;
_editTest.Gender = param.Gender;
public class Parameter
{
public double Age { get; set; }
public int Gender { get; set; }
public string Name { get; set; }
}
DetailView xml
<EditText
style="#style/InputNumbersEditText"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="44dp"
android:gravity="center_vertical|right"
android:hint="00.000"
local:MvxBind="Text EditTest.Age, Converter=Nullable;" />
TestViewModel
public class TestViewModel : BaseViewModel
{
public string? Name { get; set; }
public double? Age { get; set; }
public int? Gender { get; set; }
}
NullableValueConverter
public class NullableValueConverter : MvxValueConverter
{
public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (string.IsNullOrEmpty(value?.ToString()))
{
return parameter;
}
return value;
}
public override object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null || string.IsNullOrEmpty(value.ToString()))
{
return null;
}
return value;
}
}
private void OnMessageReceived(TestMessage obj)
{
_selectedItem= obj.messageTest;
RaisePropertyChanged(() => SelectedItem);
}
This can't work, because your are just changing the reference of _selectedItem to point to another object. But this object is not included in the list that is used to show in the recycler view. You are not updating a object, just a reference! You should definitely have a look at the basics of C# to understand this kind of data structure. E.g. Reference vs. Value Type
Your code is a bit faulty.
You SelectedItem has the type MainViewModel
Your click command gets a item of type TestViewModel
public virtual ICommand ItemSelected
{
get
{
return new MvxCommand<TestViewModel>(item =>
{
SelectedItem = item;
});
}
}
Normally this should work:
private void OnMessageReceived(TestMessage obj)
{
_selectedItem.Age= obj.messageTest.Age;
_selectedItem.Name= obj.messageTest.Name;
_selectedItem.Gender= obj.messageTest.Gender;
}
but with a TestViewModel like
public class TestViewModel : BaseViewModel
{
private string? name;
public string? Name { get{ return name; } set { SetProperty(ref name, value); } }
// same for Age and Gender
}
SetProperty sets the value and calls the OnPropertyChanged event.
Updated Answer
Assigning the _selectedItem a new TestViewModel breaks the reference link it has to the TestViewModel held in the TestsViews data source list. While assigning the individual properties maintains the reference to the orginal TestViewModel in the TestsViews list.
Orginal Answer
As you are updating the backing field, _selectedItem, so when you receive the message event the RaisePropertyChanged event defined in the set of your SelectedItem property will never run. You will have to manually trigger the RaisePropertyChanged in order to trigger the binding update.
Try changing your current method:
private void OnMessageReceived(TestMessage obj)
{
_selectedItem= obj.messageTest;
}
To raise the property changed event:
private void OnMessageReceived(TestMessage obj)
{
_selectedItem = obj.messageTest;
RaisePropertyChanged(() => SelectedItem);
}

How to refresh data grid with new search results with MVVM Light

I'm using the latest MMVM Light windows 8 binaries and VS 2012 latest updates, so all is good there. I'm new to the MVVM Light framework, so it's an adjustment.
I have a Customers page with a grid that is searched with a textbox and button - the text box is bound and the button uses a command. The data is showing up in the view model just fine. I LINQ over the Customers List and set the Customers list property - all works well. The problem is, the page doesn't refresh. When I go to another page and return to the Customers page, the searched data is displayed.
I suspect the view model is static and needs to re-instantiated.
The follow are the respective code frags:
public partial class ViewModelLocator
{
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (ViewModelBase.IsInDesignModeStatic)
{
SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();
}
else
{
SimpleIoc.Default.Register<IDataService, DataService>();
}
// Services
SimpleIoc.Default.Register<INavigationService, NavigationService>();
SimpleIoc.Default.Register<IMessenger, Messenger>();
// View Models
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<CustomersViewModel>();
SimpleIoc.Default.Register<CustomerViewModel>(true);
SimpleIoc.Default.Register<ContactsViewModel>();
}
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
public CustomersViewModel Customers
{
get
{
return ServiceLocator.Current.GetInstance<CustomersViewModel>();
}
}
public CustomerViewModel Customer
{
get
{
return ServiceLocator.Current.GetInstance<CustomerViewModel>();
}
}
public ContactsViewModel Contacts
{
get
{
return ServiceLocator.Current.GetInstance<ContactsViewModel>();
}
}
public static void Cleanup()
{
}
}
}
public class CustomersViewModel : ViewModelBase
{
private readonly IDataService _dataService;
private INavigationService _navigationService;
private IMessenger _messenger;
public RelayCommand<string> RefreshClickCommand { get; set; }
public RelayCommand<string> SearchCustomersCommand { get; set; }
public const string CustomersPropertyName = "Customers";
private ObservableCollection<Customer> _customers = null;
public ObservableCollection<Customer> Customers
{
get
{
return _customers;
}
set
{
if (_customers == value)
{
return;
}
_customers = value;
RaisePropertyChanging(CustomersPropertyName);
}
}
public const string WelcomeTitlePropertyName = "WelcomeTitle";
private string _welcomeTitle = string.Empty;
public string WelcomeTitle
{
get
{
return _welcomeTitle;
}
set
{
if (_welcomeTitle == value)
{
return;
}
_welcomeTitle = value;
RaisePropertyChanged(WelcomeTitlePropertyName);
}
}
public const string CustomerSearchTermPropertyName = "CustomerSearchTerm";
private string _customerSearchTerm = string.Empty;
public string CustomerSearchTerm
{
get
{
return _customerSearchTerm;
}
set
{
if (_customerSearchTerm == value)
{
return;
}
_customerSearchTerm = value;
RaisePropertyChanging(CustomerSearchTermPropertyName);
}
}
public Customer SelectedItem
{
set
{
Customer customer = value;
_messenger.Send<Customer>(customer, "Customer");
_navigationService.Navigate(typeof(CustomerPage));
}
}
public CustomersViewModel(IDataService dataService)
{
_navigationService = SimpleIoc.Default.GetInstance<INavigationService>();
_messenger = SimpleIoc.Default.GetInstance<IMessenger>();
_dataService = dataService;
_dataService.GetData(
(item, error) =>
{
if (error != null)
{
// Report error here
return;
}
WelcomeTitle = item.Title + "Customers";
});
GetCustomers();
InitializeCommands();
}
private void InitializeCommands()
{
RefreshClickCommand = new RelayCommand<string>((item) =>
{
GetCustomers();
});
SearchCustomersCommand = new RelayCommand<string>((item) =>
{
SearchCustomers();
});
}
private void GetCustomers()
{
_customers = _dataService.GetCustomers();
}
private void SearchCustomers()
{
var cust = _dataService.GetCustomers();
List<Customer> customers = (from c in cust
where c.CompanyName.StartsWith(_customerSearchTerm)
orderby c.CompanyName
select c).ToList();
_customers = new ObservableCollection<Customer>(customers);
}
}
<common:LayoutAwarePage x:Class="SalesAccountManager.Views.RelationshipManager.CustomersPage"
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:common="using:SalesAccountManager.Common"
xmlns:ignore="http://www.ignore.com"
xmlns:telerikGrid="using:Telerik.UI.Xaml.Controls.Grid"
xmlns:WinRtBehaviors="using:WinRtBehaviors"
xmlns:Win8nl_Behavior="using:Win8nl.Behaviors"
mc:Ignorable="d ignore"
d:DesignHeight="768"
d:DesignWidth="1366"
DataContext="{Binding Customers, Source={StaticResource Locator}}">
....
<Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Text="Customers" FontFamily="Segoe UI" FontSize="38"/>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0, 0, 100, 0">
<TextBox Height="20" Width="600" Background="White" Text="{Binding CustomerSearchTerm, Mode=TwoWay}" />
<Button Background="White" Command="{Binding SearchCustomersCommand}">
<Image Source="../../Images/Search.jpg" Height="20" Width="20"></Image>
</Button>
</StackPanel>
</Grid>
Any guidance on this would be appreciated...
Thanks!

How to retrieve an object's Property name/value pairs on a custom object?

I have a custom object with varying datatypes for each property.
I would like to be able to do something like:
public void evalCI(configurationItem CI)
{
foreach (PropertyInformation n in CI)
{
Response.Write(n.Name.ToString() + ": " + n.Value.ToString() + "</br>");
}
}
My custom object is:
public class configurationItem : IEnumerable
{
private string serial;
private string model;
private DateTime? wstart;
private DateTime? wend;
private Int32 daysLeft;
private string platform;
private string productVersion;
private string manufacturer;
private bool verificationFlag;
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
public string Serial
{
set { serial = value; }
get { return serial; }
}
public string Model
{
set { model = value; }
get { return model; }
}
public DateTime? Wstart
{
set { wstart = value; }
get { return wstart; }
}
public DateTime? Wend
{
set { wend = value; }
get { return wend; }
}
public Int32 DaysLeft
{
set { daysLeft = value; }
get { return daysLeft; }
}
public string Platform
{
set { platform = value; }
get { return platform; }
}
public string ProductVersion
{
set { productVersion = value; }
get { return productVersion; }
}
public string Manufacturer
{
set { manufacturer = value; }
get { return manufacturer; }
}
public bool VerificationFlag
{
set { verificationFlag = value; }
get { return verificationFlag; }
}
My expected output would be:
-Serial: 1234567
-Model: Mustang
-Wstart: 12/12/2005
-Wend: 12/11/2006
-DaysLeft: 0
-Platform: Car
-ProductVersion: GT
-Manufacturer: Ford
-VerificationFlag: true
At first I was getting an error that GetEnumerator() had to be implemented to use a foreach loop. The problem I keep running into is that all of the examples of Indexed Properties are of a single property with an indexable list, instead of an index for each property in the object. I was able to get intellisense to give me methods for PropertyInfo by adding:
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
However, the 2nd GetEnumerator() throws:
Compiler Error Message: CS0103: The name 'GetEnumerator' does not exist in the current context.
What am I missing here? How do I modify my object to give me the results I expect from evalCI()?
You don't need to implement IEnumerable. What you do need to do is use Reflection.
This is from memory, but I believe it would look like this:
foreach (PropertyInfo n in typeof(configurationItem).GetProperties())
{
Response.Write(string.Format("{0}: {1}<br/>", n.Name, n.GetValue(CI, null)));
}
This - the code as written - will also only give you public properties, and non-indexed properties (but it doesn't look like you have any indexed properties).

My Combobox Selected Value binding doesn't flow back in Two Way Data binding

Im Using Simple MVVM Framework to create a simple Silverlight 4.0 LOB Application.
I have an Employee List View that shows List Of all Employees in and i have in my EmployeeListViewModel some properties As Follow:
private Grade selectedGrade;
public Grade SelectedGrade
{
get { return selectedGrade; }
set
{
selectedGrade = value;
NotifyPropertyChanged(m => m.SelectedGrade);
}
}
private Religion selectedReligion;
public Religion SelectedReligion
{
get { return selectedReligion; }
set
{
selectedReligion = value;
NotifyPropertyChanged(m => m.SelectedReligion);
}
}
private ObservableCollection<Grade> grades;
public ObservableCollection<Grade> Grades
{
get { return grades; }
set
{
grades = value;
NotifyPropertyChanged(m => m.Grades);
}
}
private ObservableCollection<Religion> religions;
public ObservableCollection<Religion> Religions
{
get { return religions; }
set
{
religions = value;
NotifyPropertyChanged(m => m.Religions);
}
}
private ObservableCollection<Department> departments;
public ObservableCollection<Department> Departments
{
get { return departments; }
set
{
departments = value;
NotifyPropertyChanged(m => m.Departments);
}
}
private Employee selectedEmployee;
public Employee SelectedEmployee
{
get { return selectedEmployee; }
set
{
selectedEmployee = value;
SetCanProperties();
NotifyPropertyChanged(m => m.SelectedEmployee);
}
}
private ObservableCollection<Employee> employees;
public ObservableCollection<Employee> Employees
{
get { return employees; }
set
{
employees = value;
NotifyPropertyChanged(m => m.Employees);
}
}
private Department selectedDepartment;
public Department SelectedDepartment
{
get { return selectedDepartment; }
set
{
selectedDepartment = value;
NotifyPropertyChanged(m => m.SelectedDepartment);
}
}
now in my view i have a button to edit selected employee in my Employee List that opens up a new Child Window with the EmployeeDetails to Edit
EmployeeListViewModel viewModel;
public EmployeeListView()
{
InitializeComponent();
viewModel = (EmployeeListViewModel)DataContext;
}
and here is the edit employee Method
private void editItemButton_Click(object sender, RoutedEventArgs e)
{
// Exit if no product selected
if (viewModel.SelectedEmployee == null) return;
// Create a product detail model
EmployeeDetailViewModel detailModel =
new EmployeeDetailViewModel(viewModel.SelectedEmployee);
// set comboboxes !!
detailModel.Departments = viewModel.Departments;
detailModel.Religions = viewModel.Religions;
detailModel.Grades = viewModel.Grades;
// Start editing
detailModel.BeginEdit();
// Show EmployeeDetail view
EmployeeDetailView itemDetail = new EmployeeDetailView(detailModel);
itemDetail.Closed += (s, ea) =>
{
if (itemDetail.DialogResult == true)
{
// Confirm changes
detailModel.EndEdit();
}
else
{
// Reject changes
detailModel.CancelEdit();
}
};
itemDetail.Show();
}
now on my details Child View I have this Constractor
public EmployeeDetailView(EmployeeDetailViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel;
}
and here is my DetailsViewModel constractor
public EmployeeDetailViewModel(Employee model)
{
base.Model = model;
}
private ObservableCollection<Religion> religions;
public ObservableCollection<Religion> Religions
{
get { return religions; }
set
{
religions = value;
NotifyPropertyChanged(m => m.Religions);
}
}
private ObservableCollection<Grade> grades;
public ObservableCollection<Grade> Grades
{
get { return grades; }
set
{
grades = value;
NotifyPropertyChanged(m => m.Grades);
}
}
private ObservableCollection<Department> departments;
public ObservableCollection<Department> Departments
{
get { return departments; }
set
{
departments = value;
NotifyPropertyChanged(m => m.Departments);
}
}
after all this now comes the binding i have three comboboxes
for Departments, Religions and Grades (Which are foreign keys in my employee table)
<ComboBox ItemsSource="{Binding Departments}" DisplayMemberPath="DepartmentName" SelectedValue="{Binding Model.Emp_Department, Mode=TwoWay}" SelectedValuePath="DepartmentId"/>
<ComboBox ItemsSource="{Binding Grades}" DisplayMemberPath="GradeName" SelectedValue="{Binding Model.Emp_Grade, Mode=TwoWay}" SelectedValuePath="GradeId"/>
and so on .. The problem is that only the Departments combo box is updating the source value when i change its value
and the other combo boxes don't .. even when the binding statement is exactly the same !!
so sorry for writing so much .. but can anyone help me with this ??
thanks a lot
Unfortunately your MVVM separation is a little messed up as you are binding from the View directly to the underlying Model (meaning any business logic / validation in the ViewModel) is bypassed.
However, you seem to have everything in place so I would suggest the following:
Change your Xaml to this (note the change from SelectedValue to SelectedItem):
<ComboBox ItemsSource="{Binding Departments}" DisplayMemberPath="DepartmentName" SelectedItem="{Binding SelectedDepartment, Mode=TwoWay}"/>
<ComboBox ItemsSource="{Binding Grades}" DisplayMemberPath="GradeName" SelectedItem="{Binding SelectedGrade, Mode=TwoWay}"/>
Then within the setter of the SelectedDepartment/SelectedGrade properties, perform any required validation and then write the Id of the selected item to the properties in your (detail) model.
Hope it helps.
well here is how i do my combos:
<ComboBox ItemsSource="{Binding Path=ListPeople, UpdateSourceTrigger= PropertyChanged}" SelectedItem="{Binding Path=SelectedPerson, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="FirstName"/>
and in my viewmodel:
private ObservableCollection<Person> listPeople = new ObservableCollection<Person>();
public IEnumerable<Person> ListPeople
{
get { return this.listPeople; }
}
public Person SelectedPerson
{
get { return selectedPerson; }
set
{
selectedPerson = value;
if (selectedPerson != null)
{
NextToPayID = selectedPerson.PersonID;
}
base.RaisePropertyChanged("SelectedPerson");
}
}
see if you can use that to help!

Resources