2010-11-01 6 views
3

J'apprends Silverlight en utilisant Silverlight Unleashed + Silverlight 2.0 4.0 Unleashed et, bien, juste déconner avec elle :-)Contrôle au montage, comment procéder?

Dans le cadre de cela, je suis en train de développer ce qui devrait être un contrôle de contenu très simple : Une étiquette que vous pouvez modifier en cliquant dessus.

Je me suis inspiré d'une autre question SO (Click-to-edit in Silverlight), mais j'ai quelques problèmes liés à mon expérience avec Silverlight. :)

Je vais d'abord poster le code, puis mes questions.

Ceci est mon 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> 

et ceci est mon CodeBehind:

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

Tout d'abord, la façon dont je dois instancier mon contrôle est très maladroit et redondant.

Il existe 2 ControlTemplates (une étiquette, une zone de texte) MAIS il y a aussi un Style avec une étiquette pour l'initialisation. Si je supprime ceci (et la ligne correspodante dans le constructeur dans le codebehind), rien ne s'affiche, même si je mets le template aussi. Il doit y avoir un meilleur moyen?

Mon deuxième problème est que lorsque je place mon contrôle dans un projet de test et l'utilise, le contrôle se déplace? Il va commencer au côté gauche au milieu comme une étiquette, puis je clique dessus, et la zone de texte apparaît centrée sur la page, et à l'entrée l'étiquette réapparaît sur le côté gauche de l'écran?

EDIT: Troisièmement, une fois que je remplace l'étiquette par la zone de texte, la zone de texte n'a pas de focus, et je n'arrive pas à comprendre comment le lui donner?

Enfin, la seule façon d'arrêter l'édition est de cliquer sur "Entrée". Idéalement, je voudrais juste cliquer en dehors de la zone de texte, mais en utilisant l'événement focus perdu (comme suggéré dans le lien) semble se déclencher trop souvent pour que je puisse l'utiliser?

J'espère que certains des gourous Silverlight sont là pour m'aider! :-)

Oh, et si quelqu'un sait d'un click-to-Edit Control disponible Je pourrais utiliser/regarder, je serais très reconnaissant aussi :)

Merci à l'avance!

Répondre

4

J'espère que je vous ai bien compris. Ce dont vous avez besoin est un TextBox qui n'est pas éditable au début, mais si vous cliquez dessus, il sera éditable. Pour cela, j'ai créé un contrôle qui hérite d'un TextBox (j'ai utilisé le template vs TemplatedControl). J'ai ajouté deux états (Edit et NotEdit) et un Rectangle qui sert de calque sur le texte pour le mode non édité (pour éviter de changer le curseur de la souris sur la souris). J'ai également fait quelques missions sur les frontières. Par exemple. dans les états non édités, les bordures sont de taille 0, de sorte que la zone de texte ressemble à une étiquette.

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

Comme vous pouvez le voir, il y a deux nouveaux états, éditer et NotEdit.Donc sur le code derrière je "envoie" le contrôle initial à l'état NotEdit et ajoute deux gestionnaires, pour GotFocus et LostFocus.

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

Les gestionnaires juste "envoyer" le contrôle dans l'état défini:

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

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

Et voici le code complet 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); 
     } 
    } 

Et vous pouvez maintenant l'utiliser dans votre UserControl :

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

Ceci i s juste une implémentation rapide, donc quelques améliorations peuvent être faites. Mais j'espère, cela vous aide avec votre problème.

BR, TJ

+0

Merci beaucoup! C'est mieux que ce que j'ai trouvé! La seule chose que je voudrais faire est d'arrêter de modifier si je clique à l'extérieur, sans vraiment me concentrer sur un autre contrôle. Je suppose que cela peut être fait en utilisant un gestionnaire de clic, cependant. (J'ai aussi dû ajouter un ControlTemplate pour le ValidationToolTipTemplate dans votre code, mais pas de biggie, juste FYI!) Aussi, beaucoup de remerciements pour l'explication de ce qui se passe - tout ce que XAML peut être assez dense parfois :) À la vôtre ! – Fafnr

+0

Vous êtes les bienvenus (sry que je oublie le ValidationTooltipTemplate). Vous pouvez ajouter un gestionnaire MouseLeftButtonUp au RootVisual. (Application.Current.RootVisual.MouseLeftButtonUp + = RootVisual_MouseLeftButtonUp, ou peut-être la méthode AddHandler.Avec cela, vous pouvez obtenir des événements déjà gérés.) Là, vous pouvez vérifier, si l'événement Mouse était sur votre contrôle, ou non. Sinon, passez à l'état NotEdit. Cela devrait fonctionner, mais ce n'est pas une très bonne solution ... – TerenceJackson

+0

Je sais que c'est de l'histoire ancienne maintenant, mais le projet Silverlight a été converti en un projet WPF, et l'un des snafus est le click-to -edit zone de texte:/Pour une raison quelconque, je ne peux pas vraiment entrer/afficher du texte en l'utilisant ... Je sais que c'est une grêle, mais avez-vous des idées pourquoi ce serait? Merci encore! – Fafnr

Questions connexes