Pregunta

Tengo el siguiente escenario:

[TemplatePart(Name = GoToEditModeButtonPart, Type = typeof(DoubleClickButton))]
public class ValueBoxWithLabel : ContentControl
{
    public const string GoToEditModeButtonPart = "GoToEditModeButtonPart";

    #region LabelText Dependency Property ...

    #region IsInEditMode Dependency Property ...

    public event EventHandler<ModeChangedEventArgs> ModeChanged;

    public ValueBoxWithLabel()
    {
        DefaultStyleKey = typeof (ValueBoxWithLabel);
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        //IsInEditMode invokes ModeChanged in the dependency property
        ((DoubleClickButton) GetTemplateChild(GoToEditModeButtonPart)).DoubleClick += (sender, args) => IsInEditMode = true;
    }

    private void InvokeModeChanged(ModeChangedEventArgs e)
    {
        EventHandler<ModeChangedEventArgs> mode = ModeChanged;
        if (mode != null)
            mode(this, e);
    }
}

ValueBox es esencial un panel para cualquier caja de entrada. Ahora es simple, pero se reutilizará en toda la aplicación y contendrá un comportamiento y diseño más complejos.

El cuadro de texto como entrada es la necesidad de usar, por lo tanto, hago este control:

public class TextBoxWithLabel : ValueBoxWithLabel
{
    #region Text Dependency Property ...

    public TextBoxWithLabel()
    {
        DefaultStyleKey = typeof (TextBoxWithLabel);
    }
}

Luego tengo el Generic.xaml actual, que no funciona, pero da una idea de lo que quiero:

<ResourceDictionary>

<ControlTemplate x:Key="ValueBoxWithLabelTemplate">
    <StackPanel Style="{StaticResource ValueBoxWithLabelPanelStyle}">
        <TextBlock Style="{StaticResource LabelStyle}" Text="{TemplateBinding LabelText}" />
        <Grid>
            <ContentPresenter Content="{TemplateBinding Content}" />
            <local:DoubleClickButton Background="Black" x:Name="GoToEditModeButtonPart"></local:DoubleClickButton>
        </Grid>
    </StackPanel>
</ControlTemplate>

<Style TargetType="local:ValueBoxWithLabel">
    <Setter Property="Template" Value="{StaticResource ValueBoxWithLabelTemplate}" />
</Style>

<Style TargetType="local:TextBoxWithLabel">
    <Setter Property="Template" Value="{StaticResource ValueBoxWithLabelTemplate}" />
    <Setter Property="Content">
        <Setter.Value>
            <TextBox Style="{StaticResource ValueBoxStyle}" Text="{TemplateBinding Text}" />
        </Setter.Value>
    </Setter>
</Style>

Dado que un valleboxwithlabel se usa más con un cuadro de texto, quiero hacer un control para esto, lo que reutiliza la misma plantilla, por lo que no necesito copiar/pegar la plantilla y tener el encabezado de mantenerse al día con la misma cambios.

¿Cómo puedo reutilizar el valleboxwithLabeltEmplate y solo anular la propiedad de contenido manteniendo el resto de la plantilla?

¿Fue útil?

Solución

Es un enfoque intrigante. No lo he probado yo mismo, pero parece que el enfoque podría funcionar.

El problema que tiene actualmente es que está tratando de usar el Content propiedad del ContentPresenter. Sin embargo, eso requiere que se asigne una instancia concreta de un control que en este caso está haciendo con un TextBox. No puedes usar TemplateBinding en el TextBox Porque no es parte de un ControlTemplate.

Incluso sin el TemplateBinding problema, solo podría crear un control con él de todos modos, ya que no puede "reutilizar" la misma instancia de un TextBox en más de un lugar. Por eso tenemos plantillas en primer lugar.

Plantillas todo el camino

Resolver el problema de la plantilla no debería ser tan difícil. Lo realmente truco sería encontrar una manera de unir el control de contenido interno de los controles especializados a las propiedades de la clase especializada. Esto es difícil para así cuando no puedes usar TemplateBinding.

Primero solo describiré los cambios que al menos necesitaría hacer para obtener la representación de los controles:--

<ControlTemplate x:Key="ValueBoxWithLabelTemplate">
    <StackPanel Style="{StaticResource ValueBoxWithLabelPanelStyle}">
        <TextBlock Style="{StaticResource LabelStyle}" Text="{TemplateBinding LabelText}" />
        <Grid>
            <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" />
            <local:DoubleClickButton Background="Black" x:Name="GoToEditModeButtonPart"></local:DoubleClickButton>
        </Grid>
    </StackPanel>
</ControlTemplate>

los TextBoxWithLabel se convierte en:-

<Style TargetType="local:TextBoxWithLabel">
    <Setter Property="Template" Value="{StaticResource ValueBoxWithLabelTemplate}" />
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
                <TextBox Style="{StaticResource ValueBoxStyle}"  />
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

Creo que esto (sin probarlo) será.

El problema vinculante

Sin embargo, como puede ver el enlace en el Text Falta la propiedad. Ahora hay un par de cosas en las que puedo pensar que podrían ayudarlo a resolver este problema vinculante, pero implican abusar del DataContext o creando una subclase de ContentPresenter para ayudar a las propiedades de transferencia desde el control exterior hasta el interno. Ambos son realmente feos.

Conclusión

Para una plantilla base tan simple, probablemente esté mejor duplicando la plantilla que saltar a través de todos los aros necesarios para lograr algún tipo de reutilización.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top