Autor Beitrag
UGrohne
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Veteran
Beiträge: 5502
Erhaltene Danke: 220

Windows 8 , Server 2012
D7 Pro, VS.NET 2012 (C#)
BeitragVerfasst: Sa 21.02.09 20:11 
Ich versuche gerade einen Kategoriebaum mit einem TreeView darzustellen. Hierzu habe ich eine Klasse ProductCategoryViewModel (MVVM-Pattern), folgendermaßen aufgebaut ist:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
    public class ProductCategoryViewModel:ElementViewModel
    {
        private Product_Category category;

        #region Constructor
        public ProductCategoryViewModel(Product_Category category, string parentViewModelProperty)
            :base(parentViewModelProperty)
        {
            this.category = category;
        }
        #endregion

        #region Properties
        public string CategoryName
        {
            get { return category.Name; }
            set
            {
                category.Name = value;
                OnPropertyChanged("CategoryName");
            }
        }

        public bool HasSubcategories
        {
            get { return category.ChildCategories.Count > 0; }
        }

        private List<ProductCategoryViewModel> subCategories;
        public List<ProductCategoryViewModel> SubCategories
        {
            get
            {
                if (subCategories == null)
                {
                    var r = from c in DatabaseManager.AptusOfficeEntities.Product_Category
                            where c.ParentCategory == category
                            select c;
                    subCategories = new List<ProductCategoryViewModel>(r.Count());
                    foreach (var cat in r)
                    {
                        subCategories.Add(new ProductCategoryViewModel(cat, "SubCategories"));
                    }
                }
                return subCategories;
            }
        }
        #endregion
    }


In meiner Window-Klasse habe ich die Eigenschaft Categories, auch wieder eine List<ProductCategoryView> und folgendem XAML-Code:
ausblenden XML-Daten
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
<UserControl x:Class="AptusSolutions.AptusOffice.WpfClient.View.AllProductsView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:AptusSolutions.AptusOffice.WpfClient.ViewModel">
    <UserControl.Resources>
        <HierarchicalDataTemplate DataType="{x:Type vm:ProductCategoryViewModel}" ItemsSource="{Binding SubCategories}">
            <TreeViewItem Header="{Binding CategoryName}"/>
        </HierarchicalDataTemplate>
    </UserControl.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="auto" MaxWidth="400"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TreeView Grid.Column="0" ItemsSource="{Binding Categories}"/>
    </Grid>
</UserControl>


Alle Beispiele, die ich dazu gefunden habe, waren ähnlich aufgebaut, jedoch wird bei mir nur die oberste Ebene dargestellt und in der Ausgabe finde ich folgende Exception:
ausblenden volle Höhe Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
Eine Ausnahme (erste Chance) des Typs "System.NotSupportedException" ist in System.Data.Entity.dll aufgetreten.
System.Windows.Data Error: 16 : Cannot get 'SubCategories' value (type 'List`1') from '' (type 'ProductCategoryViewModel'). BindingExpression:Path=SubCategories; DataItem='ProductCategoryViewModel' (HashCode=49137221); target element is 'TreeViewItem' (Name=''); target property is 'ItemsSource' (type 'IEnumerable') TargetInvocationException:'System.Reflection.TargetInvocationException: Ein Aufrufziel hat einen Ausnahmefehler verursacht. ---> System.NotSupportedException: Es kann kein konstanter Wert des Typs 'AptusSolutions.AptusOffice.WpfClient.ViewModel.ProductCategoryViewModel' erstellt werden. In diesem Kontext werden nur primitive Typen ('wie z. B. 'Int32', 'String' und 'Guid'') unterstützt.
   bei System.Data.Objects.ELinq.ExpressionConverter.ConstantTranslator.TypedTranslate(ExpressionConverter parent, ConstantExpression linq)
   bei System.Data.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
   bei System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
   bei System.Data.Objects.ELinq.ExpressionConverter.MemberAccessTranslator.TypedTranslate(ExpressionConverter parent, MemberExpression linq)
   bei System.Data.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
   bei System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
   bei System.Data.Objects.ELinq.ExpressionConverter.EqualsTranslator.TypedTranslate(ExpressionConverter parent, BinaryExpression linq)
   bei System.Data.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
   bei System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
   bei System.Data.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input)
   bei System.Data.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input, DbExpressionBinding& binding)
   bei System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, DbExpression& source, DbExpressionBinding& sourceBinding, DbExpression& lambda)
   bei System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)
   bei System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)
   bei System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
   bei System.Data.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
   bei System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
   bei System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.AggregateTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)
   bei System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)
   bei System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
   bei System.Data.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
   bei System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
   bei System.Data.Objects.ELinq.ExpressionConverter.Convert()
   bei System.Data.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
   bei System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
   bei System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
   bei System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
   bei System.Data.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__2[TResult](IEnumerable`1 sequence)
   bei System.Data.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable`1 query, Expression queryRoot)
   bei System.Data.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[S](Expression expression)
   bei System.Linq.Queryable.Count[TSource](IQueryable`1 source)
   bei AptusSolutions.AptusOffice.WpfClient.ViewModel.ProductCategoryViewModel.get_SubCategories() in F:\Visual Studio 2008\Projects\AptusOffice\AptusOfficeWpf\ViewModel\ProductCategoryViewModel.cs:Zeile 48.
   --- Ende der internen Ausnahmestapelüberwachung ---
   bei System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   bei System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   bei System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
   bei System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   bei System.Reflection.RuntimePropertyInfo.GetValue(Object obj, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
   bei System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)
   bei MS.Internal.Data.PropertyPathWorker.GetValue(Object item, Int32 level)
   bei MS.Internal.Data.PropertyPathWorker.RawValue(Int32 k)'


Was mache ich falsch?
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Sa 21.02.09 21:56 
Eher ein EF- denn ein WPF-Problem: Du vergleichst zwei Product_Categorys, was er nicht in Sql umsetzen kann.
Der einfachste Fix dürfte sein, stattdessen die IDs zu vergleichen, aber keine Ahnung, ob das wirklich so gemacht wird :mrgreen: . Bei den richtigen FK Constraints sollte dir der EF-Designer allerdings automatisch entsprechende "Navigation Properties" anlegen, mit denen du überhaupt keine Query mehr brauchst:
ausblenden C#-Quelltext
1:
2:
3:
4:
subCategories =
  c.SubCategories
  .Select(cat => new ProductCategoryViewModel(cat, "SubCategories"// IEnumerable, nicht IQueryable
  .ToList();

_________________
>λ=
UGrohne Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Veteran
Beiträge: 5502
Erhaltene Danke: 220

Windows 8 , Server 2012
D7 Pro, VS.NET 2012 (C#)
BeitragVerfasst: So 22.02.09 01:46 
Oh Mann, Du hast natürlich Recht :oops:

Ich suche die ganze Zeit in WPF nach ner Lösung und erkenne gar nicht, dass es gar nicht daran liegt. Aber schon ziemlich versteckt, wenn man sich nicht den Call-Stack anschaut ...
UGrohne Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Veteran
Beiträge: 5502
Erhaltene Danke: 220

Windows 8 , Server 2012
D7 Pro, VS.NET 2012 (C#)
BeitragVerfasst: So 22.02.09 02:05 
OK, damit das hier doch noch ein WPF-Thema wird, hab ich noch ein Problem mit obigem.

Er listet mir das jetzt korrekt auf, nur: Ich kann die Elemente nicht mit einem Klick auf den Text, sondern nur auf einen (im Vergleich zu von Hand erstellten TreeViewItems) großen Abstand vor dem Text zum Expanding-Pfeil selektieren. Es sieht so aus, als ob ein leeres TreeViewItem und dahinter erst ein TextBlock mit dem Header erstellt werden, aber ich kann nicht feststellen, warum.

Hast Du da ne Idee?

//EDIT: Hat sich erledigt, habs verstanden: Er erstellt ein TreeViewItem und packt dort das Zeug aus dem DataTemplate rein und schon habe ich mein TVI im TVI. Ersetze ich es durch einen normalen TextBlock, funktionierts :autsch: