2011-02-02 22 views
11

Estoy intentando crear un Control de usuario que, dependiendo del modo que el usuario establezca en la Propiedad de dependencia, cambie el Control de usuario a un TextBlock y a otro TextBlock o un TextBlock y un TextBox. Sé que las propiedades de dependencia están obteniendo la información, pero el problema surge cuando intento establecer la plantilla correcta. Por alguna razón, la plantilla no se procesa correctamente.Condicional XAML (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> 

código subyacente:

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

    } 
} 

Gracias de antemano.

+2

Definir * "no se procesa correctamente" *. ¿Cuál es el resultado esperado y cuál es el resultado real? – Heinzi

+0

El resultado esperado sería un Bloque de texto y otro Bloque de texto o un Bloque de texto y un Cuadro de texto. Lo que obtengo es una caja con un círculo rojo y una X blanca dentro del círculo o nada. En función de cómo trato de ejecutarlo. – chris

Respuesta

11

Aquí es un ejemplo de cómo se puede crear un control condicional:

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 
} 

Aquí es su estilo que usted necesita para poner en Themes/Generic.xaml en que proyecto:

<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

Funciona muy bien, gracias! – flq

0

Es probable que necesite un IValueConverter para cambiar ese string a un ControlTemplate que se espera. No hará la búsqueda de la clave de recurso cuando se pase como una cadena vacía. Una solución diferente sería utilizar un Style para alterar la visibilidad:

<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

Puede utilizar disparadores para ajustar la plantilla. Reemplace el StackPanel en su UserControl con este ...

<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, aunque creo que los enlaces tendrán que ser originados por uno mismo y no por el DataContext (predeterminado). – Jay

+0

Intenté esto en un proyecto de muestra y las vinculaciones funcionaron tal cual. –

+2

¡Buena solución! – Chris

Cuestiones relacionadas