Как я знаю, что элемент управления Silverlight был отображен? - PullRequest
2 голосов
/ 16 мая 2011

У меня есть список, в котором отображаются названия разделов справки, которые можно добавить, и названия тем, которые можно изменить. Первоначально это было просто отображение строк, но чтобы заставить работать встроенное редактирование, я изменил его, чтобы использовать пользовательский тип, состоящий из строки и свойства InEdit, чтобы пользовательский интерфейс мог определять, отображать ли TextBlock или TextBox:

XAML:

<ListBox ItemsSource="{Binding HelpTopics, Mode=TwoWay}"
         SelectedValuePath="Description"
         SelectedValue="{Binding SelectedPageId, Mode=TwoWay}"
         SelectionChanged="ListBox_SelectionChanged">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid>
                <TextBlock Text="{Binding Description, Mode=TwoWay}" 
                           VerticalAlignment="Center"
                           MouseLeftButtonUp="TopicTextBlock_MouseLeftButtonUp"
                           Visibility="{Binding InEdit, Converter={StaticResource boolToVisibilityConverter}, ConverterParameter=contra}"/>

                <TextBox Text="{Binding Description, Mode=TwoWay}" 
                         Visibility="{Binding InEdit, Converter={StaticResource boolToVisibilityConverter}, ConverterParameter=pro}"
                         LostFocus="EditTopicTextBox_LostFocus"
                         HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

<Button Margin="5" Content="Add Topic" Command="{Binding AddTopicCommand}"/>

HelpTopics является ObservableCollection<EditableHelpTopic>.
SelectedPageId является string.
boolToVisibilityConverter - это конвертер, который делает то, что говорит.

Что работает:

  • Добавление темы создает новый элемент, добавляет его в список и переводит его в режим редактирования.
  • Двойной щелчок по существующему элементу переводит этот элемент в режим редактирования, устанавливает фокус на TextBox и выделяет весь текст, чтобы его можно было перезаписать.
  • Когда TextBox теряет фокус, редактирование сохраняется, и дисплей возвращается к TextBlock.

Что не работает:

  • При добавлении новой темы TextBox должен иметь фокус и выделенный текст, чтобы пользователь мог ввести новое имя.

Так что мой вопрос есть ли в коде точка или событие, где я знаю, что TextBox был создан и видим, чтобы я мог установить фокус и выбрать его содержимое. Я пытался подключиться к событию SelectionChanged, но когда это происходит, TextBox еще не отображалось. Я также добавил событие к методу OnAddTopicExecute в модели представления, которое я обработал в представлении, но опять-таки оно сработало до того, как стал видимым TextBox.


Ниже приведен код, который поддерживает вышеуказанный XAML. Я пытался сократить его, но, похоже, его все еще много, так что вы можете пропустить это, если вам не интересно;)

Код:

private DateTime lastClickTime = DateTime.MinValue;
private Point lastClickPosition;

private void TopicTextBlock_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
    UIElement element = sender as UIElement;

    if ((DateTime.Now - this.lastClickTime).TotalMilliseconds > 300)
    {
        this.lastClickPosition = e.GetPosition(element);
        this.lastClickTime = DateTime.Now;
    }
    else
    {
        Point position = e.GetPosition(element);
        if (Math.Abs(this.lastClickPosition.X - position.X) < 4 && Math.Abs(this.lastClickPosition.Y - position.Y) < 4)
        {
            var textBlock = sender as TextBlock;
            var editableHelpTopic = textBlock.DataContext as EditableHelpTopic;
            editableHelpTopic.InEdit = true;
            var parent = textBlock.Parent as Grid;
            TextBox textBox = parent.Children.First(c => c.GetType() == typeof(TextBox)) as TextBox;
            textBox.Focus();
            textBox.SelectAll();
        }
    }  
}

private void EditTopicTextBox_LostFocus(object sender, RoutedEventArgs e)
{
    var textBox = sender as TextBox;
    var editableHelpTopic = textBox.DataContext as EditableHelpTopic;
    editableHelpTopic.InEdit = false;

    if (!textBox.Text.Equals(editableHelpTopic.Description))
    {
        this.editViewModel.RenameTopic(textBox.Text);
    }
}

Просмотр модели:

public EditViewModel()
{
    ...
    this.AddTopicCommand = new DelegateCommand(this.OnAddTopicExecute, this.OnAddTopicCanExecute);
    ...
}

где DelegateCommand - реализация ICommand.

private void OnAddTopicExecute(object parameter)
{
    var newTopic = new EditableHelpTopic
        {
            Description = "NewTopic",
            InEdit = true
        };
    this.HelpTopics.Add(newTopic);
    this.SelectedPageId = newTopic.Description;
}

Определения:

public class EditableHelpTopic : INotifyPropertyChanged
{
    public bool InEdit { ... }
    public string Description { ... }
}

1 Ответ

3 голосов
/ 16 мая 2011

Это оказалось проще, чем я думал.

Мне просто нужно было добавить обработчик событий Loaded к TextBox:

private void EditTopicTextBox_Loaded(object sender, RoutedEventArgs e)
{
    var textBox = sender as TextBox;
    var editableHelpTopic = textBox.DataContext as EditableHelpTopic;
    if (editableHelpTopic.InEdit)
    {
        textBox.Focus();
        textBox.SelectAll();
    }
}
...