2017-10-04 4 views
0

J'essaie d'apprendre les propriétés de dépendance et les propriétés attachées, alors s'il vous plaît pardonnez-moi si vous ne trouvez aucune utilité dans ce que j'essaie de faire.WPF Propriété jointe déclencheur deux fois

J'ai une approche MVVM habituelle avec une fenêtre dont le datacontext est défini sur une VM, et View qui est un datatemplate contenant un usercontrol ciblant une telle VM. J'essaie de rendre le conteneur de fenêtre aussi bête que possible, en tant que tel j'essaie de définir certains paramètres qui résident habituellement dans la fenêtre XAML (par exemple la hauteur) via le contrôle utilisateur en utilisant les propriétés attachées.

A cette fin, j'ai créé la classe suivante où je définis la propriété ci-joint:

public static class WpfExtensions 
{ 
    public static readonly DependencyProperty ContainerHeightProperty = DependencyProperty.RegisterAttached(
     "ContainerHeight", 
     typeof(double), 
     typeof(WpfExtensions), 
     new FrameworkPropertyMetadata(300.0, FrameworkPropertyMetadataOptions.AffectsParentArrange | FrameworkPropertyMetadataOptions.AffectsParentMeasure | FrameworkPropertyMetadataOptions.AffectsRender, ContainerHeight) 
    ); 
    public static void SetContainerHeight(UIElement element, double value) 
    { 
     element.SetValue(ContainerHeightProperty, value); 
    } 
    public static double GetContainerHeight((UIElement element) 
    { 
     return (double)element.GetValue(ContainerHeightProperty); 
    } 

    private static void ContainerHeight(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     if (d is UserControl) 
     { 
      UserControl l_Control = (UserControl)d; 

      Binding l_Binding = new Binding(); 

      l_Binding.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(Window), 1); 

      l_Binding.Path = new PropertyPath("Height"); 

      l_Binding.Mode = BindingMode.OneWayToSource; 

      BindingOperations.SetBinding(d, e.Property, l_Binding);   
     } 
    } 
} 

comme vous pouvez le voir, pour obtenir le contrôle de la hauteur de la fenêtre du conteneur Je crée une fixation dans le code de la joint propriété jusqu'à la fenêtre du conteneur.

Cependant, le changement ContainerHeight est déclenché deux fois. La première fois que je reçois un changement de 300 (la valeur par défaut) à 1024 (ce qui est défini dans XAML). Ensuite, je reçois immédiatement un autre de 1024 à 300 et je ne comprends pas pourquoi.

Le code de la fenêtre est très simple:

<Window x:Class="WpfApplication.DialogWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:lcl="clr-namespace:WpfApplication" 
     Title="DialogWindow"> 
    <Window.Resources> 
     <DataTemplate DataType="{x:Type lcl:Dialog_VM}"> 
      <lcl:Dialog_VM_View /> 
     </DataTemplate> 
    </Window.Resources> 

    <ContentPresenter Content="{Binding }" /> 

</Window> 

et enfin le ViewModel simple,

<UserControl x:Class="WpfApplication.Dialog_VM_View" 
    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:lcl="clr-namespace:WpfApplication" 
    mc:Ignorable="d" 
    d:DesignHeight="300" d:DesignWidth="300" 
    lcl:WpfExtensions.ContainerHeight="1024"> 

    <StackPanel> 
     <TextBlock Text="This is a test" /> 
    </StackPanel> 

</UserControl> 
+0

Où est votre 'ContainerHeight' propriété? – Bojje

+0

WpfExtensions, premier morceau de code que j'ai collé, utilisé avec le UserControl, le troisième morceau de code que j'ai collé. – user1464603

+0

Au lieu de cette approche étrange, avez-vous envisagé de simplement définir la propriété SizeToContent de Windows? – Clemens

Répondre

1

Vous devriez lier la propriété Height de la fenêtre parent à la propriété attachée et non l'inverse , ne devriez-vous pas?

Ce jeux (la) Height Lié de la fenêtre parent à 1024 qui est la valeur de la propriété de dépendance dans le UserControl:

private static void ContainerHeight(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    if (d is UserControl) 
    { 
     UserControl l_Control = (UserControl)d; 
     if (!l_Control.IsLoaded) 
     { 
      l_Control.Loaded += L_Control_Loaded; 
     } 
     else 
     { 
      Bind(l_Control); 
     } 
    } 
} 

private static void L_Control_Loaded(object sender, RoutedEventArgs e) 
{ 
    UserControl l_Control = (UserControl)sender; 
    Bind(l_Control); 
} 

private static void Bind(UserControl l_Control) 
{ 
    Window window = Window.GetWindow(l_Control); 

    Binding l_Binding = new Binding(); 
    l_Binding.Path = new PropertyPath(WpfExtensions.ContainerHeightProperty); 
    l_Binding.Source = l_Control; 

    BindingOperations.SetBinding(window, Window.HeightProperty, l_Binding); 
} 
+0

Cela atteint exactement ce que je m'attendais. J'ai compliqué les choses en essayant de lier la cible à la source et en utilisant onewaytosource avec la cible étant le contrôle alors que comme vous l'avez montré, la liaison avec la fenêtre étant la cible et le contrôle étant la source est la bonne façon. J'ai atteint un cerveau-verrouillé aveuglé par la hiérarchie visuelle. Je vous remercie. – user1464603

+0

@ user1464603 Vous pouvez également constater qu'une liaison n'est plus nécessaire du tout. Réglez juste la hauteur de la fenêtre à la valeur actuelle de la propriété ContentHeight dans la méthode "Bind" (tant que ContentHeight ne change pas plus tard). – Clemens

+0

Désolé, débutant stackoverflow. – user1464603