2011-02-02 4 views
11

J'essaie de créer un contrôle utilisateur qui, selon le mode défini par l'utilisateur dans la propriété de dépendance, modifie le contrôle utilisateur en un TextBlock et un autre TextBlock ou un TextBlock et un TextBox. Je sais que les propriétés de dépendance obtiennent l'information, mais le problème se pose lorsque j'essaie de définir le bon modèle. Pour une raison quelconque, le modèle ne s'affiche pas correctement.XAML conditionnel (WPF)

XAML:

<UserControl x:Class="BookOrganizer.FlipBox" 
     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:my="clr-namespace:BookOrganizer" 
     mc:Ignorable="d" 
     d:DesignHeight="300" d:DesignWidth="300"> 
<StackPanel Orientation="Horizontal" Height="Auto" Width="Auto" > 
    <StackPanel.Resources> 
     <ContentControl x:Key="Box"> 
      <StackPanel Orientation="Horizontal"> 
       <TextBlock Text="{Binding Path=Title}" Height="Auto" Width="Auto" /> 
       <TextBox Text="{Binding Path=Text}" Height="Auto" Width="Auto" /> 
      </StackPanel> 
     </ContentControl> 
     <ContentControl x:Key="Block" Height="Auto" Width="Auto"> 
      <StackPanel Orientation="Horizontal" Height="Auto" Width="Auto"> 
       <TextBlock Text="{Binding Path=Title}" Height="Auto" Width="Auto" /> 
       <TextBlock Text="{Binding Path=Text}" Height="Auto" Width="Auto"/> 
      </StackPanel> 
     </ContentControl> 
    </StackPanel.Resources> 
    <ContentControl Template="{Binding Path=BoxMode}" /> 
</StackPanel> 

code Derrière:

using System; 
using System.Windows; 
using System.Windows.Controls; 

namespace BookOrganizer 
{ 
    /// <summary> 
    /// Interaction logic for FlipBox.xaml 
    /// </summary> 
    public partial class FlipBox : UserControl 
    { 
     public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
     "Title", typeof(String), typeof(FlipBox), new PropertyMetadata("nothing")); 

     public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
     "Text", typeof(String), typeof(FlipBox), new PropertyMetadata("nothing")); 

     public static readonly DependencyProperty BoxModeProperty = DependencyProperty.Register(
     "BoxMode", typeof(String), typeof(FlipBox), new PropertyMetadata("Box")); 

     public FlipBox() 
     { 
      InitializeComponent(); 
      this.DataContext = this; 
     } 

     public String Title 
     { 
      get { return (String)this.GetValue(TitleProperty); } 
      set { this.SetValue(TitleProperty, value); } 
     } 

     public String Text 
     { 
      get { return (String)this.GetValue(TextProperty); } 
      set { this.SetValue(TextProperty, value); } 
     } 

     public String BoxMode 
     { 
      get { return (String)this.GetValue(BoxModeProperty); } 
      set { this.SetValue(BoxModeProperty, value); } 
     } 

    } 
} 

Merci à l'avance.

+2

Définir * "ne rend pas correctement" *. Quelle est la production attendue et quelle est la production réelle? – Heinzi

+0

La sortie attendue serait soit un bloc de texte et un autre bloc de texte, soit un bloc de texte et une zone de texte. Ce que je reçois est une boîte avec un cercle rouge et un X blanc à l'intérieur du cercle ou rien. Basé sur comment j'essaie de l'exécuter. – chris

Répondre

11

Voici un exemple de la façon dont vous pouvez créer un contrôle conditionnel:

public class ConditionalControl : ContentControl 
{ 
    static ConditionalControl() 
    { 
     DefaultStyleKeyProperty.OverrideMetadata(typeof (ConditionalControl), new FrameworkPropertyMetadata(typeof (ConditionalControl))); 
    } 

    #region Condition DP 

    public bool Condition 
    { 
     get { return (bool) GetValue(ConditionProperty); } 
     set { SetValue(ConditionProperty, value); } 
    } 

    public static readonly DependencyProperty ConditionProperty = 
     DependencyProperty.Register("Condition", typeof (bool), typeof (ConditionalControl), new UIPropertyMetadata(false)); 

    #endregion 

    #region TrueTemplate DP 

    public DataTemplate TrueTemplate 
    { 
     get { return (DataTemplate) GetValue(TrueTemplateProperty); } 
     set { SetValue(TrueTemplateProperty, value); } 
    } 

    public static readonly DependencyProperty TrueTemplateProperty = 
     DependencyProperty.Register("TrueTemplate", typeof (DataTemplate), typeof (ConditionalControl), new UIPropertyMetadata(null)); 

    #endregion 

    #region FalseTemplate DP 

    public DataTemplate FalseTemplate 
    { 
     get { return (DataTemplate) GetValue(FalseTemplateProperty); } 
     set { SetValue(FalseTemplateProperty, value); } 
    } 

    public static readonly DependencyProperty FalseTemplateProperty = 
     DependencyProperty.Register("FalseTemplate", typeof (DataTemplate), typeof (ConditionalControl), new UIPropertyMetadata(null)); 

    #endregion 
} 

Voici c'est le style que vous avez besoin de mettre en Themes/Generic.xaml dans votre projet:

<Style TargetType="{x:Type Controls:ConditionalControl}"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type Controls:ConditionalControl}"> 
       <Border Background="{TemplateBinding Background}" 
         BorderBrush="{TemplateBinding BorderBrush}" 
         BorderThickness="{TemplateBinding BorderThickness}"> 

        <Grid> 
         <ContentPresenter x:Name="FalseContentPresenter" 
              Content="{TemplateBinding DataContext}" 
              ContentTemplate="{TemplateBinding FalseTemplate}" /> 
        </Grid> 

       </Border> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 

    <Style.Triggers> 
     <Trigger Property="Condition" 
       Value="True"> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="{x:Type Controls:ConditionalControl}"> 
         <Border Background="{TemplateBinding Background}" 
           BorderBrush="{TemplateBinding BorderBrush}" 
           BorderThickness="{TemplateBinding BorderThickness}"> 

          <Grid> 
           <ContentPresenter x:Name="TrueContentPresenter" 
                Content="{TemplateBinding DataContext}" 
                ContentTemplate="{TemplateBinding TrueTemplate}" /> 
          </Grid> 
         </Border> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Trigger> 
    </Style.Triggers> 
</Style> 
+0

Fonctionne très bien, merci! – flq

0

Vous aurez probablement besoin un IValueConverter pour changer cela string à un ControlTemplate qui est prévu. Il n'effectuera pas la recherche de la clé de ressource lorsqu'elle est passée en tant que chaîne vide. Une autre solution serait d'utiliser un Style pour modifier la visibilité:

<StackPanel Orientation="Horizontal"> 
    <TextBlock Text="{Binding Title}" /> 
    <TextBox Text="{Binding Text}"> 
      <TextBox.Style> 
       <Style TargetType="TextBox"> 
        <Setter Property="Visibility" Value="Collapsed" /> 
        <Style.Triggers> 
         <DataTrigger Binding="{Binding BoxMode}" Value="Box"> 
          <Setter Property="Visibility" Value="Visible" /> 
         </DataTrigger> 
        </Style.Triggers> 
       </Style> 
      </TextBox.Style> 
    </TextBox> 
    <TextBlock Text="{Binding Text}"> 
      <TextBlock.Style> 
       <Style TargetType="TextBlock"> 
        <Setter Property="Visibility" Value="Visible" /> 
        <Style.Triggers> 
         <DataTrigger Binding="{Binding BoxMode}" Value="Box"> 
          <Setter Property="Visibility" Value="Collapsed" /> 
         </DataTrigger> 
        </Style.Triggers> 
       </Style> 
      </TextBlock.Style> 
    </TextBlock> 
</StackPanel> 
13

Vous pouvez utiliser des triggers pour définir le modèle. Remplacez le StackPanel dans votre UserControl avec ce ...

<StackPanel Orientation="Horizontal" Height="Auto" Width="Auto" > 
     <ContentControl> 
     <ContentControl.Style> 
      <Style TargetType="{x:Type ContentControl}"> 
       <Style.Triggers> 
        <DataTrigger Binding="{Binding Path=BoxMode}" Value="Box"> 
        <Setter Property="Template"> 
         <Setter.Value> 
          <ControlTemplate> 
           <StackPanel Orientation="Horizontal" Height="Auto" Width="Auto"> 
           <TextBlock Text="{Binding Path=Title}" Height="Auto" Width="Auto" /> 
           <TextBlock Text="{Binding Path=Text}" Height="Auto" Width="Auto"/> 
           </StackPanel> 
          </ControlTemplate> 
         </Setter.Value> 
        </Setter> 
        </DataTrigger> 
        <DataTrigger Binding="{Binding Path=BoxMode}" Value="Block"> 
        <Setter Property="Template"> 
         <Setter.Value> 
          <ControlTemplate> 
           <StackPanel Orientation="Horizontal"> 
           <TextBlock Text="{Binding Path=Title}" Height="Auto" Width="Auto" /> 
           <TextBox Text="{Binding Path=Text}" Height="Auto" Width="Auto" /> 
           </StackPanel> 
          </ControlTemplate> 
         </Setter.Value> 
        </Setter> 
        </DataTrigger> 
       </Style.Triggers> 
      </Style> 
     </ContentControl.Style> 
     </ContentControl> 
    </StackPanel> 
+2

+1, bien que je pense que les liaisons devront être définies sur soi plutôt que sur le DataContext (par défaut). – Jay

+0

J'ai essayé ceci dans un exemple de projet et les fixations ont fonctionné tel quel. –

+2

Belle solution !! – Chris