2010-11-01 69 views
3

我正在学习Silverlight,使用Silverlight 2.0 Unleashed + Silverlight 4.0释放和,以及只是搞乱它:-)点击编辑控件 - 如何操作?

作为一部分,我试图开发什么应该是一个非常简单的内容控制:您可以通过点击进行编辑的标签。

我从另一个SO问题(Click-to-edit in Silverlight)中获得灵感,但我遇到了一些与我对Silverlight非常新的问题有关的问题。 :)

我会先发布代码,然后是我的问题。

这是我的XAML:

<ContentControl x:Class="MyTestProject.SilverlightControl1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:sdk="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Input" xmlns:local="clr-namespace:MyTestProject" mc:Ignorable="d" 
    d:DesignHeight="300" d:DesignWidth="400"> 
    <ContentControl.Resources> 
     <ControlTemplate x:Key="EditableLabelTextboxTemplate"> 
      <TextBox Name="UCTB" Text="{Binding Text, Mode=TwoWay}" Width="100" Height="25" ></TextBox> 
     </ControlTemplate> 
     <ControlTemplate x:Name="LabelTemplate" TargetType="local:SilverlightControl1"> 
      <sdk:Label x:Name="UCLBL" Content="{Binding Text}" /> 
     </ControlTemplate> 
     <Style TargetType="local:SilverlightControl1"> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate x:Name="LabelTemplate2" TargetType="local:SilverlightControl1"> 
         <sdk:Label x:Name="UCLBL" Content="{Binding Text}" /> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 
    </ContentControl.Resources> 
</ContentControl> 

,这是我隐藏:

所有的
public partial class SilverlightControl1 : ContentControl 
    { 
     public string Text { get; set; } 

     public SilverlightControl1() 
     { 
      this.DataContext = this; 
      Text = "Hello, World!"; 
      this.DefaultStyleKey = typeof(SilverlightControl1); 
      //Template = this.Resources["LabelTemplate"] as ControlTemplate; 
      InitializeComponent(); 
     } 

     public override void OnApplyTemplate() 
     { 
      base.OnApplyTemplate(); 
      this.MouseLeftButtonDown += HandleLabelLeftMouseDown; 
      this.KeyDown += HandleTextboxEnter; 
     } 

     public static void HandleTextboxEnter(object sender, KeyEventArgs args) 
     { 
      var ctrl = sender as SilverlightControl1; 
      if (ctrl.Template == ctrl.Resources["EditableLabelTextboxTemplate"]) 
      { 
       if (args.Key == Key.Enter) 
       { 
        ctrl.Template = ctrl.Resources["LabelTemplate"] as ControlTemplate; 
       } 
      } 
     } 

     public static void HandleLabelLeftMouseDown(object sender, MouseButtonEventArgs args) 
     { 
      var editableLabel = sender as SilverlightControl1; 
      if (editableLabel.Template != editableLabel.Resources["EditableLabelTextboxTemplate"]) 
      { 
       editableLabel.Template = editableLabel.Resources["EditableLabelTextboxTemplate"] as ControlTemplate; 
      } 
     } 
    } 

首先,我必须实例我的控制是非常笨拙的,冗余的方式。

有2个控件模板(一个标签,一个文本框)但是还有一个带初始化标签的样式。如果我删除了这个(和代码隐藏的构造函数中的对应行),即使我设置了模板,也不会呈现任何内容。一定会有更好的办法?

我的第二个问题是,当我把我的控件放在一个测试项目中并使用它时,控件移动了?它将从中间的左侧作为标签开始,然后单击它,文本框出现在页面中央,并且在屏幕左侧再次出现标签时输入该标签?

编辑: 第三,一旦我用文本框替换标签,文本框没有焦点,我不知道如何把它给它?

最后,现在停止编辑的唯一方法是点击“enter”。理想情况下,我只想在文本框之外点击,但是使用丢失的焦点事件(如链接中所示)似乎太频繁地激发我能够使用它了?

我希望有一些Silverlight专家可以帮助我! :-)

哦,应该有人知道可用的点击Edit控件,我可以用在/看的,我会非常感激太:)

提前感谢!

回答

4

我希望我能帮到你。你需要的是一开始不可编辑的文本框,但如果你点击它,它将是可编辑的。

为此,我创建了一个继承自TextBox的控件(我使用了vs模板TemplatedControl)。我添加了两个状态(Edit和NotEdit)和一个Rectangle,作为非编辑模式的文本层(用于防止在鼠标上方更改鼠标光标)。我也做了一些边界的任务。例如。在非编辑状态下,边框的大小为0,以便TextBox看起来像一个Label。

这里的XAML:

<Style TargetType="local:ClickToEditTextBox"> 
      <Setter Property="BorderThickness" Value="1"/> 
      <Setter Property="Background" Value="#FFFFFFFF"/> 
      <Setter Property="Foreground" Value="#FF000000"/> 
      <Setter Property="Padding" Value="2"/> 
      <Setter Property="BorderBrush"> 
       <Setter.Value> 
        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> 
         <GradientStop Color="#FFA3AEB9" Offset="0"/> 
         <GradientStop Color="#FF8399A9" Offset="0.375"/> 
         <GradientStop Color="#FF718597" Offset="0.375"/> 
         <GradientStop Color="#FF617584" Offset="1"/> 
        </LinearGradientBrush> 
       </Setter.Value> 
      </Setter> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="local:ClickToEditTextBox"> 
         <Grid x:Name="RootElement"> 
          <VisualStateManager.VisualStateGroups> 
           <VisualStateGroup x:Name="CommonStates"> 
            <VisualState x:Name="Normal"/> 
            <VisualState x:Name="MouseOver"/> 
            <VisualState x:Name="Disabled"> 
             <Storyboard> 
              <DoubleAnimation Storyboard.TargetName="DisabledVisualElement" Storyboard.TargetProperty="Opacity" To="1" Duration="0"/> 
             </Storyboard> 
            </VisualState> 
            <VisualState x:Name="ReadOnly"> 
             <Storyboard> 
              <DoubleAnimation Storyboard.TargetName="ReadOnlyVisualElement" Storyboard.TargetProperty="Opacity" To="1" Duration="0" /> 
             </Storyboard> 
            </VisualState> 
           </VisualStateGroup> 
           <VisualStateGroup x:Name="FocusStates"> 
            <VisualState x:Name="Focused"> 
             <Storyboard> 
              <DoubleAnimation Storyboard.TargetName="FocusVisualElement" Storyboard.TargetProperty="Opacity" To="1" Duration="0"/> 
             </Storyboard> 
            </VisualState> 
            <VisualState x:Name="Unfocused"> 
             <Storyboard> 
              <DoubleAnimation Storyboard.TargetName="FocusVisualElement" Storyboard.TargetProperty="Opacity" To="0" Duration="0"/> 
             </Storyboard> 
            </VisualState> 
           </VisualStateGroup> 
           <VisualStateGroup x:Name="ValidationStates"> 
            <VisualState x:Name="Valid"/> 
            <VisualState x:Name="InvalidUnfocused"> 
             <Storyboard> 
              <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ValidationErrorElement" Storyboard.TargetProperty="Visibility"> 
               <DiscreteObjectKeyFrame KeyTime="0"> 
                <DiscreteObjectKeyFrame.Value> 
                 <Visibility>Visible</Visibility> 
                </DiscreteObjectKeyFrame.Value> 
               </DiscreteObjectKeyFrame> 
              </ObjectAnimationUsingKeyFrames> 
             </Storyboard> 
            </VisualState> 
            <VisualState x:Name="InvalidFocused"> 
             <Storyboard> 
              <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ValidationErrorElement" Storyboard.TargetProperty="Visibility"> 
               <DiscreteObjectKeyFrame KeyTime="0"> 
                <DiscreteObjectKeyFrame.Value> 
                 <Visibility>Visible</Visibility> 
                </DiscreteObjectKeyFrame.Value> 
               </DiscreteObjectKeyFrame> 
              </ObjectAnimationUsingKeyFrames> 
              <ObjectAnimationUsingKeyFrames Storyboard.TargetName="validationTooltip" Storyboard.TargetProperty="IsOpen"> 
               <DiscreteObjectKeyFrame KeyTime="0"> 
                <DiscreteObjectKeyFrame.Value> 
                 <sys:Boolean>True</sys:Boolean> 
                </DiscreteObjectKeyFrame.Value> 
               </DiscreteObjectKeyFrame> 
              </ObjectAnimationUsingKeyFrames> 
             </Storyboard> 
            </VisualState> 
           </VisualStateGroup> 
           <!-- The new edit states --> 
           <VisualStateGroup x:Name="EditStates"> 
            <VisualState x:Name="Edit"> 
             <Storyboard> 
              <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="rectangle"> 
               <DiscreteObjectKeyFrame KeyTime="0"> 
                <DiscreteObjectKeyFrame.Value> 
                 <Visibility>Collapsed</Visibility> 
                </DiscreteObjectKeyFrame.Value> 
               </DiscreteObjectKeyFrame> 
              </ObjectAnimationUsingKeyFrames> 
             </Storyboard> 
            </VisualState> 
            <VisualState x:Name="NotEdit"> 
             <Storyboard> 
              <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderThickness)" Storyboard.TargetName="Border"> 
               <DiscreteObjectKeyFrame KeyTime="0"> 
                <DiscreteObjectKeyFrame.Value> 
                 <Thickness>0</Thickness> 
                </DiscreteObjectKeyFrame.Value> 
               </DiscreteObjectKeyFrame> 
              </ObjectAnimationUsingKeyFrames> 
             </Storyboard> 
            </VisualState> 
           </VisualStateGroup> 
          </VisualStateManager.VisualStateGroups> 
          <Border x:Name="Border" CornerRadius="1" Opacity="1" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1"> 
           <Grid> 
            <Border x:Name="ReadOnlyVisualElement" Opacity="0" Background="#5EC9C9C9"/> 
            <Border x:Name="MouseOverBorder" BorderThickness="1" BorderBrush="Transparent"> 
             <Grid> 
              <ScrollViewer x:Name="ContentElement" Padding="{TemplateBinding Padding}" BorderThickness="0" IsTabStop="False"/> 
              <Rectangle x:Name="rectangle" Fill="#02FFFFFF" /> 
             </Grid> 
            </Border> 
           </Grid> 
          </Border> 
          <Border x:Name="DisabledVisualElement" Background="#A5F7F7F7" BorderBrush="#A5F7F7F7" BorderThickness="{TemplateBinding BorderThickness}" Opacity="0" IsHitTestVisible="False"/> 
          <Border x:Name="FocusVisualElement" BorderBrush="#FF6DBDD1" BorderThickness="{TemplateBinding BorderThickness}" Margin="1" Opacity="0" IsHitTestVisible="False"/> 
          <Border x:Name="ValidationErrorElement" BorderThickness="1" CornerRadius="1" BorderBrush="#FFDB000C" Visibility="Collapsed"> 
           <ToolTipService.ToolTip> 
            <ToolTip x:Name="validationTooltip" Template="{StaticResource ValidationToolTipTemplate}" Placement="Right" 
         PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}" 
         DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}"> 
             <ToolTip.Triggers> 
              <EventTrigger RoutedEvent="Canvas.Loaded"> 
               <BeginStoryboard> 
                <Storyboard> 
                 <ObjectAnimationUsingKeyFrames Storyboard.TargetName="validationTooltip" Storyboard.TargetProperty="IsHitTestVisible"> 
                  <DiscreteObjectKeyFrame KeyTime="0"> 
                   <DiscreteObjectKeyFrame.Value> 
                    <sys:Boolean>true</sys:Boolean> 
                   </DiscreteObjectKeyFrame.Value> 
                  </DiscreteObjectKeyFrame> 
                 </ObjectAnimationUsingKeyFrames> 
                </Storyboard> 
               </BeginStoryboard> 
              </EventTrigger> 
             </ToolTip.Triggers> 
            </ToolTip> 
           </ToolTipService.ToolTip> 
           <Grid Width="12" Height="12" HorizontalAlignment="Right" Margin="1,-4,-4,0" VerticalAlignment="Top" Background="Transparent"> 
            <Path Margin="1,3,0,0" Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z" Fill="#FFDC000C"/> 
            <Path Margin="1,3,0,0" Data="M 0,0 L2,0 L 8,6 L8,8" Fill="#ffffff"/> 
           </Grid> 
          </Border> 
         </Grid> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 

正如你可以看到,有两个新的状态,编辑和NotEdit。

因此,在我后面的代码中,将控件初始化为NotEdit状态并为GotFocus和LostFocus添加两个处理程序。

this.GotFocus += ClickToEditTextBox_GotFocus; 
this.LostFocus += ClickToEditTextBox_LostFocus; 
VisualStateManager.GoToState(this, "NotEdit", false); 

处理程序刚刚定义的状态“送”的控制:

void ClickToEditTextBox_LostFocus(object sender, RoutedEventArgs e) 
     { 
      VisualStateManager.GoToState(this, "NotEdit", false); 
     } 

     void ClickToEditTextBox_GotFocus(object sender, RoutedEventArgs e) 
     { 
      VisualStateManager.GoToState(this, "Edit", false); 
     } 

这里是完整的SRC代码:

public class ClickToEditTextBox : TextBox 
    { 
     public ClickToEditTextBox() 
     { 
      this.DefaultStyleKey = typeof(ClickToEditTextBox); 
     } 

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

      this.GotFocus += ClickToEditTextBox_GotFocus; 
      this.LostFocus += ClickToEditTextBox_LostFocus; 

      VisualStateManager.GoToState(this, "NotEdit", false); 

     } 

     void ClickToEditTextBox_LostFocus(object sender, RoutedEventArgs e) 
     { 
      VisualStateManager.GoToState(this, "NotEdit", false); 
     } 

     void ClickToEditTextBox_GotFocus(object sender, RoutedEventArgs e) 
     { 
      VisualStateManager.GoToState(this, "Edit", false); 
     } 
    } 

现在你可以在你的用户控件使用:

<SilverlightApplication1:ClickToEditTextBox Text="12345" Width="100" Height="22" /> 

This i只是一个快速实施,所以可以做一些改进。但我希望,这可以帮助你解决问题。

BR,TJ

+0

非常感谢!这比我想出的要好!我猜想我唯一想做的就是停止编辑,如果我在外面点击,而不实际关注其他控件。不过,我猜测可以使用一些点击处理程序来完成。 (我也必须在你的代码中为ValidationToolTipTemplate添加一个ControlTemplate,但没有biggie,只是FYI!) 另外,非常感谢解释什么是happingin - 所有那些XAML可能有时非常密集:) 干杯! – Fafnr 2010-11-01 14:27:50

+0

不客气(我的意思是我把Forgott ValidationTooltipTemplate)。 您可以将一个MouseLeftButtonUp处理程序添加到RootVisual。 (Application.Current.RootVisual.MouseLeftButtonUp + = RootVisual_MouseLeftButtonUp;或者可能是AddHandler方法,这样你就可以处理事件了。)你可以检查鼠标事件是否在你的控件上。如果没有,请转到NotEdit状态。这应该有效,但它不是一个很好的解决方案... – TerenceJackson 2010-11-01 15:09:37

+0

我知道这是迄今为止的古代历史,但是Silverlight项目只是转换为WPF项目,其中一个是点击到 - 编辑文本框:/出于某种原因,我实际上无法使用它输入/显示任何文本...我知道这是一个冰雹,但你有什么想法,为什么会这样?再次感谢你! – Fafnr 2011-01-03 14:51:23