2011-02-02 9 views
11

Sto provando a creare un controllo utente che, in base alla modalità impostata dall'utente nella proprietà dipendenza, modifica il controllo utente in un oggetto TextBlock e in un altro TextBlock o TextBlock e TextBox. So che le proprietà di dipendenza stanno ottenendo le informazioni, ma il problema sorge quando provo a impostare il modello corretto. Per qualche motivo, il modello non viene visualizzato correttamente.XAML condizionale (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> 

Codice Dietro:

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); } 
     } 

    } 
} 

Grazie in anticipo.

+2

Definire * "non viene visualizzato correttamente" *. Qual è l'output atteso e qual è l'output effettivo? – Heinzi

+0

L'output previsto potrebbe essere un blocco di testo e un altro blocco di testo o un blocco di testo e una casella di testo. Quello che ottengo è una scatola con un cerchio rosso e una X bianca all'interno del cerchio o nulla. Basato su come provo a eseguirlo. – chris

risposta

11

Ecco un esempio di come è possibile creare un controllo condizionale:

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 
} 

Ecco il suo stile che è necessario mettere in Themes/Generic.xaml in voi Progetto:

<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

Funziona molto bene, grazie! – flq

0

È probabile che sia necessario un IValueConverter per modificare quello string su un ControlTemplate che è previsto. Non verrà eseguita la ricerca della chiave di risorsa quando viene passata come stringa vuota. Una diversa soluzione sarebbe quella di utilizzare un Style per alterare 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

È possibile utilizzare i trigger per impostare il modello. Sostituisci StackPanel nel tuo UserControl con questo ...

<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, anche se penso che i binding debbano essere originati da self piuttosto che dal DataContext (predefinito). – Jay

+0

Ho provato questo in un progetto di esempio e le associazioni hanno funzionato così com'è. –

+2

Bella soluzione !! – Chris