Управление щелчком по редактированию - как это сделать? - PullRequest
3 голосов
/ 01 ноября 2010

Я изучаю Silverlight, используя Silverlight 2.0 Unleashed + Silverlight 4.0 Unleashed и, ну, просто возиться с ним: -)

В рамках этого я пытаюсь разработать очень простой элемент управления контентом: метку, которую можно редактировать, щелкая по ней.

Я черпал вдохновение из другого SO вопроса ( Click-to-edit в 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>

и это мой 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;
            }
        }
    }

Прежде всего, способ, которым я должен создать экземпляр моего Контроля, очень неуклюж и избыточен.

Существует 2 шаблона ControlTemplate (одна метка, одно текстовое поле), но есть также стиль с меткой для инициализации. Если я удаляю это (и строку соответствующего кодирования в конструкторе в коде сзади), ничего не отображается, даже если я также установил шаблон. Должен быть лучший способ?

Моя вторая проблема заключается в том, что когда я помещаю свой элемент управления в тестовый проект и использую его, элемент управления перемещается ? Он будет начинаться с левой стороны в середине как метка, затем я щелкаю по нему, и текстовое поле отображается по центру страницы, а при вводе метка снова появляется с левой стороны экрана?

EDIT: В-третьих, когда я заменяю метку на текстовое поле, текстовое поле не имеет фокуса, и я не могу понять, как его передать?

Наконец, сейчас единственный способ прекратить редактирование - нажать «ввод». В идеале я хотел бы просто щелкнуть за пределами текстового поля, но использование события потерянного фокуса (как предлагается в ссылке) слишком часто срабатывает, чтобы я мог его использовать?

Я надеюсь, что некоторые из гуру Silverlight могут мне помочь! : -)

О, и если бы кто-то знал о доступном элементе управления, который я мог бы использовать / посмотреть, я тоже был бы очень благодарен :)

Заранее спасибо!

1 Ответ

4 голосов
/ 01 ноября 2010

Надеюсь, я вас правильно понял.Что вам нужно, так это TextBox, который не редактируется в начале, но если вы щелкните по нему, он будет редактируемым.

Для этого я создал элемент управления, который наследуется от TextBox (я использовал шаблон TemplatedControl против).Я добавил два состояния (Edit и NotEdit) и Rectangle, который действует как слой над текстом для режима без редактирования (чтобы предотвратить изменение курсора мыши при наведении курсора мыши).Я также сделал несколько заданий на границах.Например, в состояниях без редактирования границы имеют размер 0, поэтому TextBox выглядит как метка.

Вот 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>

Как видите, есть два новыхсостояния, Edit и 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);
        }
    }

И теперь вы можете использовать его в своем UserControl:

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

Это просто быстрая реализация, поэтому можно внести некоторые улучшения.Но я надеюсь, это поможет вам с вашей проблемой.

BR, TJ

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...