Pergunta

Eu tenho o seguinte cenário:

[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 é essencial um painel para qualquer caixa de entrada. É simples agora, mas será reutilizado durante todo o aplicativo e conterá comportamentos e layout mais complexos.

TextBox como entrada é o que deve ser usado; portanto, faço esse controle:

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

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

Eu tenho então o atual genérico.xaml, que não funciona, mas dá uma idéia do que eu quero:

<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>

Como um ValueBoxwithlabel é mais usado com uma caixa de texto, quero fazer um controle para isso, que reutiliza o mesmo modelo, para que não preciso copiar/colar o modelo e ter a cabeça de manter os dois atualizados com o mesmo mudanças.

Como posso reutilizar o ValueBoxWithLabeltemplate e substituir apenas a propriedade de conteúdo que mantém o restante do modelo?

Foi útil?

Solução

É uma abordagem intrigante. Eu não tentei, mas parece que a abordagem pode funcionar.

O problema que você tem atualmente é que você está tentando usar o Content propriedade do ContentPresenter. No entanto, isso requer uma instância concreta de um controle que seja atribuído que, neste caso, você está fazendo com um TextBox. Você não pode usar TemplateBinding no TextBox Porque não faz parte de um ControlTemplate.

Mesmo sem o TemplateBinding Problema, você só seria capaz de criar um controle com ele de qualquer maneira, já que você não pode "reutilizar" a mesma instância de um TextBox em mais de um lugar. É por isso que temos modelos em primeiro lugar.

Modelos todo o caminho

Resolver o problema de modelos não deve ser tão difícil. A coisa realmente complicada seria encontrar uma maneira de vincular o controle de conteúdo interno de controles especializados às propriedades da classe especializada. É difícil para isso quando você não pode usar TemplateBinding.

Primeiro, vou apenas descrever as mudanças que você precisaria pelo menos para fazer para obter os controles renderizando:-

<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>

o TextBoxWithLabel torna-se:-

<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>

Acho que isso (sem testá -lo) renderizará.

A questão vinculativa

No entanto, como você pode ver a ligação no Text Propriedade está ausente. Agora, há algumas coisas em que posso pensar que podem ajudá -lo a resolver esse problema de ligação, mas eles envolvem abusar do DataContext ou criando uma subclasse de ContentPresenter Para ajudar as propriedades de repasse do controle externo ao interno. Ambos são realmente feios.

Conclusão

Para um modelo de base tão simples, você provavelmente está melhor duplicando o modelo do que pular por todos os aros necessários para obter algum tipo de reutilização.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top