2010-04-06 64 views
3

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

谢谢

回答

4

创建文本框控件模板和更改文本框的外观,你喜欢当控制的重点也有内部的内容。

+0

简单高效! 谢谢,正是我在寻找的! – fra 2010-04-06 11:37:20

0

我知道的太迟,但对于未来的观众:

该解决方案使用原来的TextBox控件模板,并增加了其与文本框的标签属性时文本框文本为空替换Text属性值的功能。这是相当复杂的造型,但它的作品! (无需任何代码后面!!):

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