none
Problem bei mehrmaligem Entleeren der ItemsSource einer WPF ComboBox mittels Reflection RRS feed

  • Frage

  • Hallo,

    Ich arbeite an einer WPF-Applikation in der aufgrund von Dynamik Zugriffe auf Steuerelement-Properties mittels Reflection erledigt werden.

    Nun habe ich kürzlich eine Methode geschrieben, um die ItemsSource einer WPF Combobox entweder zu setzen oder auszutauschen.

    Im Falle des Austauschs der Liste werden vor dem erneuten Füllen erst einmal die vorhandenen Items entfernt.

    Dies funktioniert aber leider nur beim ersten Mal.

    Versuche ich dies zwei Mal nacheinander zu machen, schlägt der zweite Versuch fehl (bei clear.Invoke(itemsToClear, null)).

    Ich bin derzeit etwas ratlos, was da passiert.

    Hier meine Methode zum Füllen der Items:

            /// <summary>
            /// This method is filling the itemssource of the frameworkelement.
            /// </summary>
            /// <param name="table">A datatable with data for the items.</param>
            public void ElementFillItemssource(FrameworkElement element, DataTable table)
            {
                if (table == null || table.Rows.Count < 1)
                    return;
    
                System.Collections.ObjectModel.ObservableCollection<KeyAndValue> items = new System.Collections.ObjectModel.ObservableCollection<KeyAndValue>();
    
                foreach (DataRow row in table.Rows)
                {
                    items.Add(new KeyAndValue() { Key = row["Listkey"].ToString(), Value = row["Listvalue"].ToString() });
                }
    
                // Clears the items before setting the collection.
                if (element.GetType().GetProperty("Items") != null)
                {
                    PropertyInfo targetProperty = element.GetType().GetProperty("Items");
                    var itemsToClear = targetProperty.GetValue(element, null);
                    MethodInfo clear = targetProperty.PropertyType.GetMethod("Clear");
                    if (clear != null)
                    {
                        clear.Invoke(itemsToClear, null);
                    }
                }
    
                element.GetType().GetProperty("ItemsSource").SetValue(element, items);
            }
    

    Und hier die Fehlermeldung, die ich beim zweiten Versuch erhalte:

    System.Reflection.TargetInvocationException wurde nicht behandelt.
      HResult=-2146232828
      Message=Ein Aufrufziel hat einen Ausnahmefehler verursacht.
      Source=mscorlib
      StackTrace:
           bei System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
           bei System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
           bei System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
           bei System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
           bei WPFDesignerPrototyp.CommonMethods.ElementFillItemssource(FrameworkElement element, DataTable table) in C:\svn_checkout\WPFVSDesignerPrototyp\WPFDesignerPrototyp\WPFDesignerPrototyp\CommonMethods.cs:Zeile 33.
           bei WPFDesignerPrototyp.ChangeTextProperties.SetDropDownListProperties(FrameworkElement element) in C:\svn_checkout\WPFVSDesignerPrototyp\WPFDesignerPrototyp\WPFDesignerPrototyp\ChangeTextProperties.cs:Zeile 496.
           bei WPFDesignerPrototyp.ChangeTextProperties.SetElementTextProperties(FrameworkElement element) in C:\svn_checkout\WPFVSDesignerPrototyp\WPFDesignerPrototyp\WPFDesignerPrototyp\ChangeTextProperties.cs:Zeile 166.
           bei WPFDesignerPrototyp.ChangeElementProperties.setTextOfTheElement(Object sender, RoutedEventArgs e) in C:\svn_checkout\WPFVSDesignerPrototyp\WPFDesignerPrototyp\WPFDesignerPrototyp\ChangeElementProperties.xaml.cs:Zeile 198.
           bei System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
           bei System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
           bei System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
           bei System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
           bei System.Windows.Controls.Primitives.ButtonBase.OnClick()
           bei System.Windows.Controls.Button.OnClick()
           bei System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
           bei System.Windows.UIElement.OnMouseLeftButtonUpThunk(Object sender, MouseButtonEventArgs e)
           bei System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
           bei System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
           bei System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
           bei System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
           bei System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)
           bei System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)
           bei System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
           bei System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
           bei System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
           bei System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
           bei System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
           bei System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)
           bei System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
           bei System.Windows.Input.InputManager.ProcessStagingArea()
           bei System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
           bei System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
           bei System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
           bei System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
           bei System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
           bei MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
           bei MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
           bei System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
           bei System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
           bei System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
           bei MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
           bei MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
           bei System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
           bei System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
           bei System.Windows.Application.RunDispatcher(Object ignore)
           bei System.Windows.Application.RunInternal(Window window)
           bei System.Windows.Application.Run(Window window)
           bei System.Windows.Application.Run()
           bei WPFDesignerPrototyp.App.Main() in C:\svn_checkout\WPFVSDesignerPrototyp\WPFDesignerPrototyp\WPFDesignerPrototyp\obj\Debug\App.g.cs:Zeile 0.
           bei System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
           bei System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
           bei Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
           bei System.Threading.ThreadHelper.ThreadStart_Context(Object state)
           bei System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
           bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
           bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
           bei System.Threading.ThreadHelper.ThreadStart()
      InnerException:
           HResult=-2146233079
           Message=Der Vorgang ist während der Verwendung von "ItemsSource" ungültig. Verwenden Sie stattdessen "ItemsControl.ItemsSource", um auf Elemente zuzugreifen und diese zu ändern.
           Source=PresentationFramework
           StackTrace:
                bei System.Windows.Controls.ItemCollection.Clear()
           InnerException:

    Dienstag, 20. September 2016 10:26

Antworten

  • Hallo Tom,

    Ich habe inzwischen eine Lösung gefunden.

    Bevor man die Items entfernt muss man die ItemsSource auf NULL setzen.

    Dann kann man sooft die Liste umstellen wie man will.

    Hier noch der Code, der vor dem Löschen der Items eingefügt werden muss:

                if (element.GetType().GetProperty("ItemsSource") != null)
                {
                    element.GetType().GetProperty("ItemsSource").SetValue(element, null);
                }
    
    Vielen Dank für Deine Tipps!


    Dienstag, 20. September 2016 15:17

Alle Antworten

  • Hallo Patrick,

    bei Controls wie der ComboBox darf immer nur ItemsSource oder Items gesetzt sein. Wenn du nun einmal ItemsSource zuweist, dann kannst du die Clear-Methode nicht mehr auf Items aufrufen, da dieses nun von ItemsSource verwaltet wird.

    Auch wenn du alles dynamisch zuweisen musst, so kannst du gewissen Rahmenbedingungen festlegen. Beispielsweise das Items nicht gesetzt sein darf. Entsprechend kannst du das leeren der Items-Eigenschaft einfach weg lassen.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    Dienstag, 20. September 2016 11:25
    Moderator
  • Wenn ich den Code zum Löschen der Items auskommentiere bekomme ich beim erneuten Setzen der ItemsSource (wenn diese bereits gefüllt ist) die folgende Fehlermeldung:

      InnerException:
           HResult=-2146233079
           Message=Die Items-Auflistung muss vor dem Verwenden von "ItemsSource" leer sein.
           Source=PresentationFramework
           StackTrace:
                bei System.Windows.Controls.ItemCollection.SetItemsSource(IEnumerable value, Func`2 GetSourceItem)
                bei System.Windows.Controls.ItemsControl.OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
                bei System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
                bei System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
                bei System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
                bei System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
                bei System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal)
                bei System.Windows.Controls.ItemsControl.set_ItemsSource(IEnumerable value)
           InnerException:

    Deswegen hatte ich das Löschen der Items ja eingebaut.

    Dienstag, 20. September 2016 14:10
  • Hallo Patrick,

    irgendwo muss Items ja gesetzt werden. Kannst du das entfernen? Wenn ja, wäre das die einfachste Lösung.

    Sonst fällt mir als Idee nur ein den if-Block in einen try...catch-Block zu setzen und ggf. entstehende Fehler abzufangen. Das wäre nicht die schönste Lösung, sollte aber funktionieren.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    Dienstag, 20. September 2016 14:52
    Moderator
  • Hallo Tom,

    Ich habe inzwischen eine Lösung gefunden.

    Bevor man die Items entfernt muss man die ItemsSource auf NULL setzen.

    Dann kann man sooft die Liste umstellen wie man will.

    Hier noch der Code, der vor dem Löschen der Items eingefügt werden muss:

                if (element.GetType().GetProperty("ItemsSource") != null)
                {
                    element.GetType().GetProperty("ItemsSource").SetValue(element, null);
                }
    
    Vielen Dank für Deine Tipps!


    Dienstag, 20. September 2016 15:17