2009-03-09 19 views
52

Estoy en el proceso de crear mi primera aplicación WPF real (es decir, la primera destinada a ser utilizada por alguien más que yo), y todavía estoy volviendo mi cabeza la mejor manera de hacer cosas en WPF. Se trata de una aplicación de acceso a datos bastante sencilla que utiliza el aún bastante nuevo Entity Framework, pero no he podido encontrar mucha orientación en línea sobre la mejor manera de utilizar estas dos tecnologías (WPF y EF) juntas. Así que pensé en descartar cómo me estoy acercando, y ver si alguien tiene mejores sugerencias.Mejores prácticas para usar Entity Framework con WPF DataBinding

  • estoy usando Entity Framework con SQL Server 2008. La EF me parece a la vez mucho más complicado de lo que debe ser, y aún no está madura, pero LINQ to SQL es aparentemente muerto, por lo También podría usar la tecnología en la que MS parece enfocarse.

  • Esta es una aplicación simple, por lo que no he (todavía) visto apropiado para construir una capa de datos separada a su alrededor. Cuando quiero llegar a los datos, utilizo consultas bastante simples LINQ a la entidad, por lo general directamente de mi código subyacente, por ejemplo:

    var families = from family in entities.Family.Include("Person") 
          orderby family.PrimaryLastName, family.Tag 
          select family; 
    
  • LINQ-a-Entidad consultas devuelven un resultado IOrderedQueryable, que doesn 't refleja automáticamente los cambios en los datos subyacentes, por ejemplo, si agrego un nuevo registro a través de código para el modelo de datos de la entidad, la existencia de este nuevo registro no se refleja automáticamente en los diversos controles que hacen referencia a la consulta Linq. En consecuencia, estoy lanzando los resultados de estas consultas en un ObservableCollection, para captar los cambios de datos subyacentes:

    familyOC = new ObservableCollection<Family>(families.ToList()); 
    
  • que a continuación en el mapa los ObservableCollection a un CollectionViewSource, de modo que pueda hacer funcionar el filtrado, clasificación, etc., sin tener que volver a la base de datos.

    familyCVS.Source = familyOC; 
    familyCVS.View.Filter = new Predicate<object>(ApplyFamilyFilter); 
    familyCVS.View.SortDescriptions.Add(new System.ComponentModel.SortDescription("PrimaryLastName", System.ComponentModel.ListSortDirection.Ascending)); 
    familyCVS.View.SortDescriptions.Add(new System.ComponentModel.SortDescription("Tag", System.ComponentModel.ListSortDirection.Ascending)); 
    
  • continuación Ato los diversos controles y para qué, no para que CollectionViewSource:

    <ListBox DockPanel.Dock="Bottom" Margin="5,5,5,5" 
        Name="familyList" 
        ItemsSource="{Binding Source={StaticResource familyCVS}, Path=., Mode=TwoWay}" 
        IsSynchronizedWithCurrentItem="True" 
        ItemTemplate="{StaticResource familyTemplate}" 
        SelectionChanged="familyList_SelectionChanged" /> 
    
  • Cuando necesito añadir o borrar registros/objetos, lo hago manualmente por lo tanto los datos de entidad modelo, y la ObservableCollection:

    private void DeletePerson(Person person) 
    { 
        entities.DeleteObject(person); 
        entities.SaveChanges(); 
        personOC.Remove(person); 
    } 
    
  • general estoy usando StackPanel y DockPanel controles para posicionar elementos. A veces usaré una Grilla, pero parece difícil de mantener: si desea agregar una nueva fila a la parte superior de su grilla, debe tocar cada control directamente alojado en la grilla para indicarle que use una nueva línea. Uggh. (Microsoft nunca pareció tener el concepto DRY.)

  • Casi nunca utilizo el diseñador VS WPF para agregar, modificar o colocar controles. El diseñador de WPF que viene con VS es algo vagamente útil para ver cómo se verá tu formulario, pero incluso entonces, bueno, no realmente, especialmente si estás usando plantillas de datos que no son vinculantes para los datos que están disponibles en tiempo de diseño. Si necesito editar mi XAML, lo tomo como un hombre y lo hago de forma manual.

  • La mayor parte de mi código real está en C# en lugar de XAML. Como mencioné elsewhere, completamente aparte del hecho de que aún no estoy acostumbrado a "pensar" en él, XAML me parece un lenguaje desagradable y torpe, que también viene con un pobre soporte de diseñador y intellisense, y que no se puede depurar Uggh. En consecuencia, cada vez que puedo ver claramente cómo hacer algo en C# code-behind que no puedo ver fácilmente cómo hacerlo en XAML, lo hago en C#, sin disculpas.Se ha escrito mucho acerca de cómo es una buena práctica casi nunca usar código subyacente en la página WPF (por ejemplo, para el manejo de eventos), pero hasta ahora al menos, eso no tiene sentido para mí en absoluto. ¿Por qué debería hacer algo en un lenguaje feo y torpe con una sintaxis espantosa, un editor asombrosamente malo y prácticamente ningún tipo de seguridad, cuando puedo usar un lenguaje agradable y limpio como C# que tiene un editor de clase mundial, casi perfecto? Intellisense, y la seguridad de tipo sin precedentes?

Así que ahí es donde estoy. ¿Alguna sugerencia? ¿Me estoy perdiendo partes importantes de esto? ¿Algo que realmente debería pensar haciendo de manera diferente?

+0

vs2010/fw4.0: parece que ItemsSource debe estar vinculado a familyCVS.View (en lugar de familyCVS) –

Respuesta

19

es necesario implementar un patrón de repositorio para separar las preocupaciones de WPF de EF

continuación, puede utilizar los genéricos para reducir la complejidad de EF para el manejo de CollectionViewSource

Un repositorio bien diseñado debería reducir los niveles de código y permitir que cualquier ORM sea sustituido (requerido para pruebas)

Algunas ideas para esto son aquí

http://blog.nicktown.info/2008/12/10/using-a-collectionviewsource-to-display-a-sorted-entitycollection.aspx

+0

Esta es probablemente la gran pieza que me faltaba, y parece valiosa. Gracias. –

+0

El enlace al final de esta respuesta ahora está muerto. – Cylindric

+1

Cierto, pero Wayback Machine [todavía tiene una copia] (http://web.archive.org/web/20130924230947/http://blog.nicktown.info/2008/12/10/using-a-collectionviewsource- to-display-a-sorted-entitycollection.aspx) (¡también considere donar!). – sorrell

4

Mis recomendaciones son, si es posible, utilizar Expression Blend para diseñar su interfaz, en lugar de Code Behind y en lugar de utilizar el diseñador de Visual Studio, le ahorrará mucho tiempo. También trate de repensar usando C# en lugar de xaml. Xaml no es tan feo si lo haces como "WPF Way". Muchas veces, cuando creo que es más fácil usar el código detrás en lugar de xaml, es porque lo estoy haciendo de la manera incorrecta y necesito replantearme cómo debería funcionar mejor con WPF/xaml. Xaml es genial una vez que te acostumbras. También utilicé el marco de entidades, que aún no es muy bueno. Prefiero NHibernate.

+0

Voy a intentar con el XAML. Pero es difícil superar el hecho de que los editores de XAML son de la edad de piedra (¡¡no intelisense en Blend !! ??) y que la sintaxis de XAML es fea. Yeccch. –

+7

Editar XAML siempre me da la sensación de comer brócoli crudo, sin salsa. Presumiblemente es bueno para mí, pero sabe como si estuviera comiendo un árbol. –

7

Además, no creo que necesite hacer una ToList() aquí. Creo que ObservableCollection() toma un IEnumerable que las familias ya son. Si hace una lista ToList y luego la pasa a ObservableCollection, entonces creo que recorrerá todos sus registros dos veces.

familyOC = new ObservableCollection<Family>(families.ToList()); 

lugar, trate de esto, lo que debería ser un poco más rápido:

familyOC = new ObservableCollection<Family>(families); 
+0

Gracias. Lo agregué al solucionar un error diferente, y nunca lo saqué. –

5

entiendo de dónde vienes. Este article by Josh Smith me ayudó a cambiar (o comenzar a cambiar) la mentalidad para que pueda beneficiarse de WPF en lugar de verlo como un marco extraño, obstructivo, difícil de depurar y antipático.

1

Otra herramienta podría ser BindableLINQ

Bindable LINQ es un conjunto de extensiones para LINQ que añadir el enlace de datos y cambiar las capacidades de propagación a nivel LINQ consulta

2

seguí este enlace de mi blog y quería mencionar algo otra cosa que encontré con EF. Algo fuera de tema, pero no totalmente.

He notado algunos problemas de rendimiento loco con EF al utilizar .Include. MS explica por qué en un artículo en su sitio web, así que en realidad comencé a cambiar la mayor parte de mi código para usar el método .Load.

Porque es una tarea tediosa y porque no pude encontrar otra manera de hacerlo ... Creé mi propio método llamado "IncludeByRoundTrip". Lo que hace es tomar una ruta de objeto y asegura que se cargue la ruta completa.El resultado final es el mismo que cuando se usa incluir sin embargo detrás de las escenas, simplemente estoy llamando a Load en todas las propiedades en el gráfico de objetos.

Sería similar a hacer algo como order.Load ("Customer.Address") si existiera tal mecanismo. De cualquier manera, compruébalo en mi blog y cuéntame tus hallazgos. Sería curioso ver si otros han notado ralentizaciones usando Include y si tiene otros enfoques para atacar la situación.

Hay más información sobre mi solución en: http://blog.nicktown.info/2009/07/27/method-to-load-an-entire-object-graph-using-adonet-entity-framework.aspx.

Nuevamente, lo siento, esto fue un poco fuera de tema, pero espero con interés sus respuestas.

Cuestiones relacionadas