2016-12-03 2 views
1

Ich habe eine einfache UserControl, das ein Symbol und Text anzeigt:Wie an Eigenschaften eines UserControl in einem anderen UserControl binden?

<UserControl x:Class="IconLabel" 
     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" 
     mc:Ignorable="d" 
     d:DesignHeight="26" d:DesignWidth="200" DataContext="{Binding RelativeSource={RelativeSource Self}}"> 
    <Grid> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="Auto"/> 
      <ColumnDefinition Width="1*"/> 
     </Grid.ColumnDefinitions> 
     <Image x:Name="imgIcon" Source="{Binding Path=IconPath}" Stretch="UniformToFill" Width="26" Height="26" Margin="3,0" /> 
     <Label Content="{Binding Path=LabelText}" Margin="5,0" Grid.Column="1" /> 
    </Grid> 
</UserControl> 

Der Code-behind definiert zwei DependencyProperties, die von außen gebunden sein sollen:

Public Class IconLabel 

    Public Property IconPath As String 
     Get 
      Return GetValue(IconPathProperty) 
     End Get 
     Set(ByVal value As String) 
      SetValue(IconPathProperty, value) 
     End Set 
    End Property 

    Public Shared ReadOnly IconPathProperty As DependencyProperty = DependencyProperty.Register("IconPath", GetType(String), GetType(IconLabel), New PropertyMetadata("")) 

    Public Property LabelText As String 
     Get 
      Return GetValue(LabelTextProperty) 
     End Get 
     Set(ByVal value As String) 
      SetValue(LabelTextProperty, value) 
     End Set 
    End Property 

    Public Shared ReadOnly LabelTextProperty As DependencyProperty = DependencyProperty.Register("LabelText", GetType(String), GetType(IconLabel), New PropertyMetadata("LabelText")) 
End Class 

, die so weit in Ordnung funktioniert . Ich kann seine Eigenschaften in XAML festlegen und sie sind richtig Gewöhnung:

<local:IconLabel LabelText="Test"/> 

Allerdings würde ich jetzt diese Kontrolle gerne Wiederverwendung in einem anderen UserControl, die seine Funktionalität leicht um zeigt einen Fortschrittsbalken erweitert

<UserControl x:Class="IconLabelProgress" 
     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:local="clr-namespace:myApp" 
     mc:Ignorable="d" 
     d:DesignHeight="26" d:DesignWidth="600" DataContext="{Binding RelativeSource={RelativeSource Self}}"> 
    <Grid> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="4*" MaxWidth="300"/> 
      <ColumnDefinition Width="6*"/> 
     </Grid.ColumnDefinitions> 
     <local:IconLabel IconPath="{Binding Path=IconPath}" LabelText="{Binding Path=PropName}" /> 
     <ProgressBar Value="{Binding Path=ActualValue}" Minimum="0" Maximum="10" Margin="5" Height="16" VerticalAlignment="Top" Grid.Column="1" /> 
    </Grid> 
</UserControl> 

mit dem folgenden Code-behind: neben ihm (ich habe dies kurz zum Zwecke des Beispiels gehalten)

Public Class IconLabelProgress 

    'These are just meant to be passed along to the IconLabel 
    Public Property IconPath As String 
     Get 
      Return GetValue(IconPathProperty) 
     End Get 
     Set(ByVal value As String) 
      SetValue(IconPathProperty, value) 
     End Set 
    End Property 

    Public Shared ReadOnly IconPathProperty As DependencyProperty = DependencyProperty.Register("IconPath", GetType(String), GetType(IconLabelProgress), New PropertyMetadata("")) 

    Public Property PropName As String 
     Get 
      Return GetValue(PropNameProperty) 
     End Get 
     Set(ByVal value As String) 
      SetValue(PropNameProperty, value) 
     End Set 
    End Property 

    Public Shared ReadOnly PropNameProperty As DependencyProperty = DependencyProperty.Register("PropName", GetType(String), GetType(IconLabelProgress), New PropertyMetadata("PropName")) 

    'This one is new 
    Public Property ActualValue As Double 
     Get 
      Return GetValue(ActualValueProperty) 
     End Get 
     Set(ByVal value As Double) 
      SetValue(ActualValueProperty, value) 
     End Set 
    End Property 

    Public Shared ReadOnly ActualValueProperty As DependencyProperty = DependencyProperty.Register("ActualValue", GetType(Double), GetType(IconLabelProgress), New PropertyMetadata(0.0)) 
End Class 

Wenn ich versuche jetzt dieses Steuerelement zu instanziiert und in einem Wert für das Etikett der inneren IconLabel Kontrolle, wie dies passiert:

<local:IconLabelProgress x:Name="ilp1" PropName="Test" ActualValue="5.0" /> 

dann wird es nicht „Test“ zeigt auf dem Etikett und stattdessen zurückgreifen zu seinem Standard, der über PropertyMetadata("LabelText") spezifiziert wurde. Die ActualValue wird jedoch korrekt verwendet.

Wie kann ich die äußere Kontrolle den Wert auf den verschachtelten übergeben?

Antwort

2

Als allgemeine Regel gilt, nie explizit die DataContext Eigenschaft eines Usercontrol gesetzt, wie man mit

<UserControl x:Class="IconLabel" ... 
    DataContext="{Binding RelativeSource={RelativeSource Self}}"> 

Doing so verhindert effektiv eine Datacontext von den Eltern Usercontrol erbt, z.B. hier

<local:IconLabel LabelText="{Binding Path=PropName}" ... /> 

wo PropName erwartet wird, eine Eigenschaft, in der übergeordneten Datacontext zu sein.


Statt explizit ein Usercontrol DataContext Einstellung, seine "interne" Bindungen schreiben mit einem RelativeSource wie

<Label Content="{Binding Path=LabelText, 
       RelativeSource={RelativeSource AncestorType=UserControl}}" ... /> 
+0

Siehe auch [diese Antwort] (http: // Stackoverflow.com/a/40674448/1136211). – Clemens

+0

Das scheint bei mir nicht zu funktionieren. Durch das Entfernen des 'DataContext' und das direkte Setzen der' RelativeSource' zeigt 'IconLabel' bei direkter Verwendung die Werte nicht an (ohne das äußere' IconLabelProgress'). Der Inhalt des Labels bleibt leer. –

+0

Sorry, mein Schlechter. Ersetzen Sie "RelativeSource Self" durch "RelativeSource AncestorType = UserControl". – Clemens

0

Standardmäßig (und Sie haben nichts anderes angegeben) wird die Bindung von den Objekten DataContext aufgelöst. So sucht Ihr IconLabel eine Eigenschaft mit dem Namen IconPath auf seinem DataContext.

Um festzulegen, dass der Platz für die Eigenschaft zu suchen, die äußere Kontrolle ist, können Sie ElementName auf die Bindung und stellen Sie einen Namen Eigenschaft auf dem IconLabelProgress oder Sie ein RelativeSource wie in dem zweiten Beispiel der akzeptierte Antwort in How do I use WPF bindings with RelativeSource angeben hinzufügen .

Ich hoffe, es hilft.

Verwandte Themen