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