WPF:选中后标签到TextBox

时间:2010-04-06 07:13:07

标签: wpf

我想创建一个看起来像visual studio的简单设计师。 具体来说,我希望我的项目具有与VS中相同的行为:当它们未被选中时,会显示一个简单的标签/文本块,当它们被选中时,文本框允许我编辑该值。 哪种方法最好?

谢谢

2 个答案:

答案 0 :(得分:4)

为TextBox创建一个控件模板,并在控件聚焦或内置内容时根据需要更改TextBox的外观。

答案 1 :(得分:0)

我知道太晚了,但对未来的观众来说:

此解决方案使用原始TextBox控件模板,并添加一项功能,当 TextBox文本为空时,将Text属性值替换为TextBox的Tag属性。这是相当复杂的造型,但它的工作原理! (没有任何代码!!):

<Style x:Key="TextBoxPlaceHolder" BasedOn="{x:Null}" TargetType="{x:Type TextBox}">
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Padding" Value="1"/>
    <Setter Property="AllowDrop" Value="true"/>
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
    <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
    <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <Microsoft_Windows_Themes:ListBoxChrome x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" SnapsToDevicePixels="true">
                    <ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                    </Microsoft_Windows_Themes:ListBoxChrome>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                    </Trigger>
                    <Trigger Property="IsFocused" Value="False">
                        <Setter Property="Text">
                            <Setter.Value>
                                <MultiBinding Converter="{StaticResource TextBoxPlaceHolderConverter}">
                                    <Binding RelativeSource="{RelativeSource Self}" Path="Text" />
                                    <Binding RelativeSource="{RelativeSource Self}" Path="Tag" />
                                </MultiBinding>
                            </Setter.Value>
                        </Setter>                                   
                    </Trigger>
                    <Trigger Property="IsFocused" Value="True">
                        <Setter Property="Text">
                            <Setter.Value>
                                <MultiBinding Converter="{StaticResource TextBoxPlaceHolderConverter}" ConverterParameter="True">
                                    <Binding RelativeSource="{RelativeSource Self}" Path="Text" />
                                    <Binding RelativeSource="{RelativeSource Self}" Path="Tag" />
                                </MultiBinding>
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Value="True">
                                <Condition.Binding>
                                    <MultiBinding Converter="{StaticResource StringsEqualMultiConverter}" Mode="OneWay">
                                        <Binding RelativeSource="{RelativeSource Self}" Path="Text" />
                                        <Binding RelativeSource="{RelativeSource Self}" Path="Tag" />
                                    </MultiBinding>
                                </Condition.Binding>
                            </Condition>
                            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsFocused}" Value="False"/>
                        </MultiDataTrigger.Conditions>
                        <Setter Property="Foreground" Value="#FF7C7C80"/>
                        <Setter Property="FontStyle" Value="Italic"/>
                    </MultiDataTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

这两个提供了转换器:

public class TextBoxPlaceHolderConverter : IMultiValueConverter
{
    private static object s_OriginalTag;

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        s_OriginalTag = values[1];
        var actualText = values[0] as string;
        var textToReturn = actualText ?? string.Empty;
        var tagText = values[1] is string ? values[1] as string : null;
        if (!(parameter is string && parameter.ToString() == "True"))
        {
            if (actualText != null && tagText != null)
            {
                if (actualText.Length == 0) // no text
                {
                    textToReturn = tagText;
                }
                else
                {
                    textToReturn = actualText;
                }
            }
        }
        else
        {
            if (actualText == tagText)
            {
                textToReturn = string.Empty;
            }
        }

        return textToReturn;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        object[] toReturn = new object[2];
        toReturn[0] = value;
        toReturn[1] = s_OriginalTag;

        return toReturn;
    }
}

public class StringsEqualMultiConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        var stringToCompare = string.Empty;

        if (values != null)
        {
            if (values.Length > 0 && values[0] is string)
            {
                stringToCompare = values[0] as string;
            }
        }

        var boolToReturn = values.Aggregate(true, (current, value) => current && (value is string && value.ToString().Equals(stringToCompare)));
        return boolToReturn;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}