databinding combobox in Dataform Silverlight using MVVM in Update

5.8k views Asked by At

I have Master/Detail – datagrid/dataform and after select item it shows in dataform for update, but I have a problem with databinding or populating combox with departments and set SelectedEmployee.departmentid as selectedvalue.

Here 2 questions now:

1. In EmployeeViewModel this code just doesn’t work and the question why?

  private ObservableCollection<department> _departments;
        public ObservableCollection<department> Departments
        {
            get { return _departments; }
            set
            {
                _departments = value;
                RaisePropertyChanged("Departments");
            }
        }

But this code works fine

   private ObservableCollection<department> _departments;
        public ObservableCollection<department> Departments
        {
            get {

                if (_departments == null)
                {
                    _departments = new ObservableCollection<department> {
                        new department()
                        { id = 1, departmentname = "Technical " + 1, },
                        new department()
                        { id = 2,  departmentname = "Technical " + 2, },
                        new department()
                        { id = 3,  departmentname = "Technical " + 3, }                    
                    };
                }
                  return _departments; 
            }
            set
            {
                _departments = value;
                RaisePropertyChanged("Departments");
            }
        }

2. Behavior of Combobox inside and outside DataForm is different. Outside it works, inside it doesn’t. I think here need to use Source in ItemsSource, but I don’t know how. So there is another question is how to fix it?

employeeView.xaml

<navigation:Page    xmlns:local="clr-namespace:departmentTechManager"
            x:Class="departmentTechManager.Views.employeeView" 
                   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"
                   mc:Ignorable="d"
                   xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
                   d:DesignWidth="820" d:DesignHeight="780"
                   Title="employees"
                   Style="{StaticResource PageStyle}"

            xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" 
            xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
            xmlns:mvvmlightcmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.SL4"
            xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
            xmlns:dataformtoolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit" 

            DataContext="{Binding employeeStatic, Source={StaticResource Locator}}">

<data:DataGrid Grid.Row="0" x:Name="dgEmployees" CanUserSortColumns="true"
                                             IsReadOnly="true" AutoGenerateColumns="true"
                                             ItemsSource="{Binding Employees}"
                                             SelectedItem="{Binding SelectedEmployee, Mode=TwoWay}"  Margin="0,36,-123,0"></data:DataGrid>
<dataformtoolkit:DataForm x:Name="dfDetails"
      CurrentItem="{Binding SelectedEmployee}" AutoGenerateFields="False"
      CommitButtonContent="Save" CommandButtonsVisibility="Edit, Commit, Cancel">
      <dataformtoolkit:DataForm.EditTemplate>
                      <DataTemplate>
                        <StackPanel>
                           <dataformtoolkit:DataField Label="name">
    <TextBox Text="{Binding name, Mode=TwoWay}" /></dataformtoolkit:DataField>

      <dataformtoolkit:DataField Label="departments">


            <ComboBox ItemsSource="{Binding Departments}"  
        DisplayMemberPath="departmentname"
            SelectedValuePath="id"  
            SelectedValue="{Binding Path=SelectedEmployee.departmentid, Mode=TwoWay}" />


     </dataformtoolkit:DataField>
      </StackPanel>
     </DataTemplate>
            </dataformtoolkit:DataForm.EditTemplate>
            <i:Interaction.Triggers><i:EventTrigger EventName="EditEnded">
                <mvvmlightcmd:EventToCommand Command="{Binding SaveEmployeesCommand}"/>
               </i:EventTrigger></i:Interaction.Triggers>
            </dataformtoolkit:DataForm>

In ViewModelLocator.cs:

 public ViewModelLocator()
        {

            _sp = ServiceProviderBase.Instance;

            Createdepartment();

            Createemployee();

        }

#region EmployeeViewModel
private static EmployeeViewModel _employee;

public static EmployeeViewModel employeeStatic
{
    get
    {
        if (_employee == null)
        {
            Createemployee();
        }

        return _employee;
    }
}

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
    "CA1822:MarkMembersAsStatic",
    Justification = "This non-static member is needed for data binding purposes.")]
public EmployeeViewModel employee
{
    get
    {
        return employeeStatic;
    }
}

public static void Clearemployee()
{
    //do it later
    //_employee.Cleanup();
    _employee = null;
}

public static void Createemployee()
{
    if (_employee == null)
    {
        _employee = new EmployeeViewModel(_sp.PageConductor, _sp.EmployeeDataService);
    }
}
#endregion

#region DepartmentViewModel
        private static DepartmentViewModel _department;

        public static DepartmentViewModel departmentStatic
        {
            get
            {
                if (_department == null)
                {
                    Createdepartment();
                }

                return _department;
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
            "CA1822:MarkMembersAsStatic",
            Justification = "This non-static member is needed for data binding purposes.")]
        public DepartmentViewModel department
        {
            get
            {
                return departmentStatic;
            }
        }

        public static void Cleardepartment()
        {
            //do it later
            //_department.Cleanup();
            _department = null;
        }

        public static void Createdepartment()
        {
            if (_department == null)
            {
                _department = new DepartmentViewModel(_sp.PageConductor, _sp.DepartmentDataService);
            }
        }

        #endregion

Can somebody help me?

combox is just empty. but now i can populate it with Departments like so:

departmentTechManagerDomainService.metadata.cs

 [MetadataTypeAttribute(typeof(employee.employeeMetadata))]
        public partial class employee
        {
     [Include]
     public department department { get; set; }
     public Nullable<int> departmentid { get; set; }
     public string name { get; set; }
        } 

departmentTechManagerDomainService.cs

public IQueryable<employee> GetEmployees()
        {return this.ObjectContext.employees.Include("department").OrderBy(e=>e.name);}

here is ViewModel code:

        private ObservableCollection<department> _departments;
        public ObservableCollection<department> Departments
        {
            get { return _departments; }
            set
            {
                _departments = value;
                RaisePropertyChanged("Departments");
            }
        }

        private department _selectedDepartment;
        public department SelectedDepartment
        {
            get { return _selectedDepartment; }
            set
            {
                _selectedDepartment = value;
                RaisePropertyChanged("SelectedDepartment");
            }
        }

private void InitializeModels()
        {
            Employees = new ObservableCollection<employee>();
            SelectedEmployee = new employee();
            NewEmployee = new employee();

            //new
            Departments = new ObservableCollection<department>();
            SelectedDepartment = new department();

        }

private void GetEmployeesCallback(IEnumerable<employee> employees)
        {
            if (employees != null)
            {
                foreach (var employee in employees)
                {
                    Employees.Add(employee);
                    //new
                    if (!Departments.Contains(employee.department))
                        Departments.Add(employee.department);

                }
                if (Employees.Count > 0)
                {
                    SelectedEmployee = Employees[0];
                }

            }
        }

I make Departments distinct, but here is only departments those already have been selected, but here aren't those that haven't been selected yet, and still combobox is not populated with departments in DataForm. ?!

3

There are 3 answers

1
rojorm On BEST ANSWER

I've got the solution for this question. here it is.

4
Snowbear On

2nd question - it looks like combobox inside and outside of dataform receives different DataContext and hence trying to locate Departments properties on different sources. It is not clear how to fix it since you haven't shown most of your ViewModels.

Pay attention to the VS output window, it usually provides very detailed info regarding binding errors and I'm assuming there are binding errors in your case.

Try modifying your department related bindings in following way:

<ComboBox ItemsSource="{Binding DataContext.Departments, RelativeSoruce={RelativeSource AncestorType={x:Type localViews:employeeView}}}" />

Where localViews should be an xml-namespace for departmentTechManager.Views. Try the same trick for SelectedItem binding.

0
user1066421 On

In Edit Template, Source must need to be mention with ViewModel Name

   <ComboBox Grid.Row="2" Grid.Column="1"
    ItemsSource="{Binding Path=Accounts, Source={StaticResource MyAccountViewModel}, Mode=TwoWay}" />