Laden...

WPF - Problem mit Visual Tree

Erstellt von itstata vor 12 Jahren Letzter Beitrag vor 12 Jahren 1.275 Views
I
itstata Themenstarter:in
302 Beiträge seit 2008
vor 12 Jahren
WPF - Problem mit Visual Tree

Hallo,

ich habe ein ziemliches Problem in meiner WPF - MVVM-Anwendung. Beim zweiten Öffnen eines Fensters bekomme ich folgende Exception:> Fehlermeldung:

Invalid Operation Exception: Specified element is already the logical child of another element. Disconnect it first.

hier noch der StackTrace:> Fehlermeldung:

at System.Windows.FrameworkElement.ChangeLogicalParent(DependencyObject newParent)
at System.Windows.FrameworkElement.AddLogicalChild(Object child)
at System.Windows.Controls.ContentControl.OnContentChanged(Object oldContent, Object newContent)
at System.Windows.Controls.ContentControl.OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
at System.Windows.Data.BindingExpressionBase.Invalidate(Boolean isASubPropertyChange)
at System.Windows.Data.BindingExpression.TransferValue(Object newValue, Boolean isASubPropertyChange)
at System.Windows.Data.BindingExpression.Activate(Object item)
at System.Windows.Data.BindingExpression.AttachToContext(AttachAttempt attempt)
at System.Windows.Data.BindingExpression.MS.Internal.Data.IDataBindEngineClient.AttachToContext(Boolean lastChance)
at MS.Internal.Data.DataBindEngine.Task.Run(Boolean lastChance)
at MS.Internal.Data.DataBindEngine.Run(Object arg)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.DispatcherOperation.InvokeImpl()
at System.Threading.ExecutionContext.runTryCode(Object userData)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Windows.Threading.DispatcherOperation.Invoke()
at System.Windows.Threading.Dispatcher.ProcessQueue()
at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Window.ShowHelper(Object booleanBox)
at System.Windows.Window.ShowDialog()
at VBApp.Presentation.Views.RechtListWindow.ShowDialog(Object owner) in C:\Users\Itstata\Documents\Visual Studio 2010\Projects\VBApp\VBApp.Presentation\Views\RechtListWindow.xaml.cs:line 33

Wie zu sehen ist, wird die Exception genau beim "ShowDialog" ausgelöst. Mir ist aber völlig unklar, wo ich ein Element ein zweites mal irgendwo reinhänge. Der StackTrace bleibt auch verdächtig beim "Content"-Property hängen.

Das Fenster, welches über "ShowDialog" geöffnet wird sieht folgendermaßen aus:

<Window x:Class="VBApp.Presentation.Views.RechtListWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    MinWidth="500" MinHeight="250" Width="1000"  SizeToContent="Height" ShowInTaskbar="False" Icon="{StaticResource EditWindowImageSource}" WindowStartupLocation="CenterOwner">
    <Window.Title>Rechte konfigurieren</Window.Title>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="400" MinWidth="{Binding Content.MinWidth, ElementName=RechtViewPresenter}"/>
        </Grid.ColumnDefinitions>
        <ContentControl Content="{Binding RechtListView}" Grid.Row="0" Grid.Column="0" Margin="0,0,7,0"/>
        <ScrollViewer VerticalScrollBarVisibility="Auto" Grid.Row="0" Grid.Column="1">
            <StackPanel>
                <GroupBox>
                    <ContentControl x:Name="RechtViewPresenter" Content="{Binding RechtView}"/>
                </GroupBox>
            </StackPanel>
        </ScrollViewer>
        <GridSplitter HorizontalAlignment="Right" VerticalAlignment="Stretch" Width="4" Grid.Row="0" Grid.Column="0"/>
    </Grid>
</Window>

Auf der linken Seite ist eine Liste die beim Auswählen rechts in einer zweiten Sicht Details zu dem Element anzeigt. Wenn ich jetzt den Content der Liste auskommentiere kommt die Exception nicht:


<!--<ContentControl Content="{Binding RechtListView}" Grid.Row="0" Grid.Column="0" Margin="0,0,7,0"/>-->

Ich vermute daher das Problem in dieser Sicht, denn im Codebehind ist nur der Context des Datenmodells eingebunden - keine weitere Logik.

Diese besagte Liste ist leider sehr trivial. Ich denke nicht, dass dort ein Fehler sein kann:


<UserControl x:Class="VBApp.Presentation.Views.RechtListView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"             
             xmlns:dat="clr-namespace:System.Windows.Data;assembly=PresentationFramework"
             xmlns:vb ="clr-namespace:VBApp.UserControls"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="400">
    <Grid>
        <ListView ItemsSource="{Binding Personen}" SelectedItem="{Binding SelectedPerson}">
            <ListView.View>
                <GridView>
                    <GridViewColumn DisplayMemberBinding="{Binding Vorname}" Header="Vorname" Width="150"/>
                    <GridViewColumn DisplayMemberBinding="{Binding Nachname}" Header="Nachname" Width="150"/>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</UserControl>

Das ViewModel dahinter ist auch nicht gerade hohe Programmierkunst:


  public class RechtListViewModel : SecuredViewModel<IRechtListView>
    {
        private readonly IEntityService entityService;
        private Person selectedPerson;

        [ImportingConstructor]
        public RechtListViewModel(IRechtListView view, IEntityService entityService, ISecurityService securityService)
            : base(view, securityService)
        {
            this.entityService = entityService;
        }

        public List<Person> Personen { get { return this.entityService.Personen.Where(p => p.Mitarbeiter).ToList(); } }

        public Person SelectedPerson
        {
            get { return this.selectedPerson; }
            set
            {
                if (this.selectedPerson!= value)
                {
                    this.selectedPerson= value;
                    RaisePropertyChanged("SelectedPerson");
                }
            }
        }
    }

Hat vielleicht jemand noch eine Idee, woran es liegen könnte?

6.862 Beiträge seit 2003
vor 12 Jahren

Hallo,

du bindest UI Elemente, in deinem Fall das UserControl, und ein UI Element darf wie die Meldung schon sagt, nur einmal angezeigt werden. Daher auch die Exception bei

Beim zweiten Öffnen eines Fensters bekomme ich folgende Exception:

Die Lösung ist ganz einfach. Binde nicht die View, sondern das entsprechende ViewModel das durch die View angezeigt werden soll, und die View gibst du als Template vor.
Das gleiche auch hier

<ContentControl x:Name="RechtViewPresenter" Content="{Binding RechtView}"/>
 

wenn RechtView, wie man dem Namen nach vermuten könnte, ein UI Element ist.

Content sind immer nur die Daten die angezeigt werden sollen, und als Template wird angegeben wie sie angezeigt werden sollen.

Baka wa shinanakya naoranai.

Mein XING Profil.

I
itstata Themenstarter:in
302 Beiträge seit 2008
vor 12 Jahren

Vielen Dank,

ist genau korrekt "RechtView" ist direkt das User-Control. Ich werd mir die Templatelösung mal anschauen.