Silverlight MVVM - 如何使用ViewModel声明性地在DataGrid CellEditingTemplate中绑定ComboBox?

时间:2010-07-07 18:42:29

标签: silverlight mvvm silverlight-4.0

我正在尝试使用ViewModel以声明方式绑定DataGrid CellEditingTemplate中的ComboBox。 ComboBox没有受到约束。我做错了什么?

XAML:

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"
    xmlns:data="clr-namespace:SilverlightApplication1"
    mc:Ignorable="d"
    x:Class="SilverlightApplication1.EmployeeDetail"
    Width="640" Height="480">

    <UserControl.Resources>
        <data:EmployeeDetailsViewModel
            x:Key="ViewModel"
            d:IsDataSource="True" />
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource ViewModel}}" Background="White">

        <sdk:DataGrid ItemsSource="{Binding Employees,Mode=TwoWay}" AutoGenerateColumns="False" CanUserSortColumns="True" CanUserReorderColumns="True" CanUserResizeColumns="True" GridLinesVisibility="All" Height="317" HorizontalAlignment="Left" Margin="12,136,0,0" Name="EmployeesGrid" VerticalAlignment="Top" Width="605">
            <sdk:DataGrid.Columns>


<!-- snipped from brevity -->

                <sdk:DataGridTemplateColumn Header="Status">
                    <sdk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding EmployeeStatus.Description}" TextWrapping="Wrap"></TextBlock>
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellTemplate>
                    <sdk:DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <ComboBox ItemsSource="{Binding Path=EmployeeStatuses}" SelectedItem="{Binding EmployeeStatus, Mode=TwoWay}" />
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellEditingTemplate>
                </sdk:DataGridTemplateColumn>

            </sdk:DataGrid.Columns>
        </sdk:DataGrid>
        <TextBlock x:Name="SearchLabel" HorizontalAlignment="Left" Margin="12,95,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="106" Height="34"><Run FontWeight="Bold" Text="Search By Name: "/><Run FontSize="9.333" Text="(Last, First)"/></TextBlock>
        <TextBox x:Name="SearchParam" HorizontalAlignment="Left" Margin="144,101,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="162"/>
        <Button x:Name="SearchButton" Content="Search" HorizontalAlignment="Right" Margin="0,102,242,0" VerticalAlignment="Top" Width="75" Click="SearchButton_Click"/>    


    </Grid>
</UserControl>

查看模特:

using System.Collections.ObjectModel;
using SilverlightApplication1.EmployeeService;
using SilverlightApplication1.ViewModels;

namespace SilverlightApplication1
{
    public class EmployeeDetailsViewModel : ViewModelBase
    {
        readonly IEmployeeServiceAgent _serviceAgent;
        ObservableCollection<EmployeeStatus> _employeeStatuses { get; set; }
        ObservableCollection<Employee> _employees { get; set; }

        public EmployeeDetailsViewModel() : this(new EmployeeServiceAgent()) { }
        public EmployeeDetailsViewModel(IEmployeeServiceAgent serviceAgent)
        {
            if (!IsDesignTime)
            {
                _serviceAgent = serviceAgent;
                GetAllEmployees();
                GetEmployeeStatuses();
            }

        }

        public ObservableCollection<Employee> Employees
        {
            get { return _employees; }
            set
            {
                if(_employees!=value)
                {
                    _employees = value;
                    OnNotifyPropertyChanged("Employees");
                }
            }
        }

        public ObservableCollection<EmployeeStatus> EmployeeStatuses
        {
            get { return _employeeStatuses; }
            set
            {
                if (_employeeStatuses != value)
                {
                    _employeeStatuses = value;
                    OnNotifyPropertyChanged("EmployeeStatuses");
                }
            }
        }

        private void GetAllEmployees()
        {
            _serviceAgent.GetAll((s, e) => Employees = e.Result);
        }

        private void GetEmployeeStatuses()
        {
            _serviceAgent.GetEmployeeStatuses((s, e) => EmployeeStatuses = e.Result);
        }

    }
}

更新

这似乎不对,但我想通过重新引用ItemSource绑定中的ViewModel来找到如何使绑定工作:

<ComboBox ItemsSource="{Binding Source={StaticResource ViewModel},Path=EmployeeStatuses}"
                                      DisplayMemberPath="Description"
                                      SelectedItem="{Binding EmployeeStatus, Mode=TwoWay}"  />

但是,我现在遇到的问题是SelectedItem没有绑定!我做错了什么?

2 个答案:

答案 0 :(得分:2)

问题是人们遇到的常见问题。当您在列的数据模板中时,您不再绑定视图模型。此时,您的数据上下文是EmployeeStatus对象(没有要绑定的EmployeeStatuses属性)。

因此,为了使组合框绑定工作,您可以使用ElementName = LayoutRoot将树绑定回根ViewModel。

更新:以下是绑定的完整语法:

{Binding DataContext.EmployeeStatuses,ElementName = LayoutRoot}

Update2:我实际上也遇到了这个问题,并且有一个workaround you have to implement来获取元素名称绑定在数据网格内部工作。

答案 1 :(得分:0)

如果Bryant的解决方案不起作用(在SL4中),请使用静态资源。请看这个链接:http://blog.digitaltools.com/post/2011/05/06/Binding-a-Datagride28099s-ComboBox.aspx

或者,通过在xaml中创建静态资源:http://forums.silverlight.net/post/370135.aspx