Проблема с привязкой данных в xaml через доменную службу RIA - PullRequest
0 голосов
/ 19 июля 2010

У меня есть структура сущностей с отношениями «многие ко многим» между клиентами и контактами.

Я создал класс обслуживания домена и вручную добавил следующий метод.

 public Customer GetCustomerById(int Id)
 {
     return this.ObjectContext.Customer.Include("Contacts").SingleOrDefault(s => s.Id == Id);
 }

Теперь я хочу создать страницу, которая показывает мне информацию о клиенте и список контактов, связанных с этим клиентом.

У меня есть следующее в codebehind of customerdetails.xaml, чтобы прочитать параметр Id, который передается вpage.

public int CustomerId
{
    get { return (int)this.GetValue(CustomerIdProperty); }
    set { this.SetValue(CustomerIdProperty, value); }
}

public static DependencyProperty CustomerIdProperty = DependencyProperty.Register("CustomerId", typeof(int), typeof(CustomerDetails), new PropertyMetadata(0));

// Executes when the user navigates to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    if (this.NavigationContext.QueryString.ContainsKey("Id"))
    {
        CustomerId = Convert.ToInt32(this.NavigationContext.QueryString["Id"]);
    }
}

Я использую следующий xaml для страницы:

<Grid x:Name="LayoutRoot" DataContext="{Binding ElementName=customerByIdSource, Path=Data}">
    <riaControls:DomainDataSource Name="customerByIdSource" AutoLoad="True" QueryName="GetCustomerById">
        <riaControls:DomainDataSource.QueryParameters>
            <riaControls:Parameter ParameterName="Id" Value="{Binding ElementName=CustomerDetailsPage, Path=CustomerId}" />
        </riaControls:DomainDataSource.QueryParameters>
        <riaControls:DomainDataSource.DomainContext>
            <sprint:Customer2DomainContext/>
        </riaControls:DomainDataSource.DomainContext>
    </riaControls:DomainDataSource>
    <StackPanel x:Name="CustomerInfo" Orientation="Vertical">
        <StackPanel Orientation="Horizontal" Margin="3,3,3,3">
            <TextBlock Text="Id"/>
            <TextBox x:Name="idTextBox" Text="{Binding Id}" Width="160"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="3,3,3,3">
            <TextBlock Text="Name"/>
            <TextBox x:Name="nameTextBox" Text="{Binding Name}" Width="160"/>
        </StackPanel>

        <ListBox ItemsSource="{Binding Contact}" DisplayMemberPath="FullName" Height="100" />
    </StackPanel>
</Grid>

Когда я делаю это, текстовые поля красиво заполняются привязкой данных, но список остается пустым.

Два вопроса:

  1. Могу ли я как-то указать тип возврата запроса GetCustomerById, чтобы я мог видеть имена при указании привязки через графический интерфейс свойств?

  2. Что я здесь не так делаю?Почему мой ListBox не заполнен?Я иду по этому пути правильно, или мне нужно также установить привязку данных для списка в codebehind?Если так, то как?Я не нашел, как программно получить доступ к свойству Contacts через источник данных домена.

Я использую Silverlight и Entity Framework 4.

1 Ответ

0 голосов
/ 20 июля 2010

Я нашел ответ на свой вопрос 2:

Свойство ассоциации Contacts не включено в создаваемые типы объектов службы домена.Вы должны указать атрибут [Include] для их включения.Однако для атрибута include требуется атрибут [Association].Вы не можете указать атрибут [Association], потому что это отношение «многие ко многим», а для атрибута ассоциации требуется указать внешние ключи.

Решение состоит в том, чтобы обернуть ваши объекты в объект передачи данных (DTO).Мне не нужно было вносить серьезные изменения в код, который уже был в моем вопросе.Единственное, что изменилось, это поиск Заказчика в классе обслуживания домена:

public CustomerDTO GetCustomerById(int Id)
{
    return new CustomerDTO(this.ObjectContext.Customers.Include("Contacts").SingleOrDefault(s => s.Id == Id));
}

Основная часть решения заключалась в том, чтобы внести изменения в классы DTO в базовую модель структуры сущности:

[DataContract]
public partial class CustomerDTO : Customer
{

    public CustomerDTO() { }
    public CustomerDTO(Customer customer)
    {
        if (customer != null)
        {
            Id = customer.Id;
            Name = customer.Name;
            CustomerContacts = new Collection<ContactDTO>();
            foreach (Contact d in customer.Contacts)
            {
                CustomerContacts.Add(new ContactDTO(d, Id));
            }
        }
    }

    [DataMember]
    [Include]
    [Association("CustomerContacts", "CustomerId", "Id")]
    public Collection<ContactDTO> CustomerContacts
    {
        get;
        set;
    }
}

[KnownType(typeof(CustomerDTO))]
public partial class Customer
{
}

[DataContract()]
public partial class ContactDTO : Contact
{
    public ContactDTO() { }
    public ContactDTO(Contact contact, int customerId)
    {
        if (contact != null)
        {
            Id = contact.Id;
            FullName = contact.FullName;
            CustomerId = customerId;
        }
    }

    [DataMember]
    public int CustomerId { get; set; }
}

[KnownType(typeof(ContactDTO))]
public partial class Contact
{
}

Атрибуты KnownType, DataMember и DataContract были необходимы для того, чтобы это работало.В действительности создание экземпляров объектов потребует немного большего копирования свойств в конструкторах.Есть ли простой способ избежать кода, который делает явную копию?Я открыт для предложений.

Я надеялся избежать введения дополнительных классов, но это кажется неизбежным в случае отношения «многие ко многим» из-за обязательного атрибута Association, которому нужен внешний ключСпецификация;в моем случае Contact.CustomerId.

Кто-нибудь может сделать лучше (== меньше кода)?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...