Проблемы пользовательских элементов управления WPF ListBox - PullRequest
2 голосов
/ 13 августа 2011

В WPF я создаю простой пользовательский элемент управления для моей программы TODO. Следует сделать следующее:

  • Отображается как ListBox с кнопкой «Добавить и удалить» над ним.
  • Кнопки Добавить и Удалить должны добавлять и удалять элементы из моего базового класса.
    • у меня это работает
  • После нажатия клавиши F2 я хочу, чтобы элементы списка превратились в элемент управления TextBox.

Мои основные вопросы / Вопросы:

  • На OnKeyDown я получаю сообщение об ошибке: Эта операция действительна только для элементов, к которым применен этот шаблон. Как мне обойти это? Здесь я хочу нажать F2 и сделать так, чтобы TextBox был видимым, а метка - невидимой.
  • Есть ли лучший способ сделать это? Если моим элементом управления является контейнер для кнопок и текстового поля, не следует ли мне наследовать от ListBox? Должен ли я вместо этого наследовать от Control и сделать его контейнером?

    • Если это так, как мне его реализовать? Использую ли я в основном следующий код в стиле, удаляю переопределения, такие как OnKeyDown, и вместо этого регистрирую событие KeyDown для текстового поля? Я попробую после этого поста, но дайте мне знать, если у вас есть какие-либо советы.

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

<!-- In my MainWindow.XAML -->
<TaskDashControls:ListBoxWithAddRemove x:Name="listBoxItems" Grid.Row="1" Grid.Column="3" Grid.RowSpan="3"
        ItemsSource="{Binding}">
    <TaskDashControls:ListBoxWithAddRemove.ItemTemplate>
        <DataTemplate>
            <DockPanel>
                <Button DockPanel.Dock="Left" Click="SelectItemClick">SELECT</Button>
                <TextBlock x:Name="LabelDescription" Visibility="Visible"  DockPanel.Dock="Left" Text="{Binding Description}" Height="25" Width="150" />
                <TextBox x:Name="EditableDescription" Visibility="Collapsed" DockPanel.Dock="Left" Text="{Binding Description}" Height="25" Width="150" />
                <Button DockPanel.Dock="Left" Click="EditTaskItemClick">EDIT</Button>
            </DockPanel>
        </DataTemplate>
    </TaskDashControls:ListBoxWithAddRemove.ItemTemplate>
</TaskDashControls:ListBoxWithAddRemove>

Я удалил DataTemplate, чтобы переместить его в пользовательский элемент управления:

<!-- In my MainWindow.XAML -->
<TaskDashControls:ListBoxWithAddRemove x:Name="listBoxItems" Grid.Row="1" Grid.Column="3" Grid.RowSpan="3"
        ItemsSource="{Binding}"/>

Вот пользовательский элемент управления в Generic.XAML:

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TaskDash.Controls">


<SolidColorBrush x:Key="WindowBackgroundBrush" Color="#FFF" />
<SolidColorBrush x:Key="SolidBorderBrush" Color="#888" />
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE" />
<SolidColorBrush x:Key="DisabledBorderBrush" Color="#AAA" />


<Style TargetType="{x:Type TextBox}">
    <Setter Property="Margin" Value="2" />
</Style>


<Style x:Key="{x:Type local:ListBoxWithAddRemove}" TargetType="{x:Type local:ListBoxWithAddRemove}">
    <Setter Property="Margin" Value="3" />
    <Setter Property="SnapsToDevicePixels" Value="True"/>
    <Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
    <Setter Property="MinWidth" Value="120"/>
    <Setter Property="MinHeight" Value="20"/>
    <Setter Property="AllowDrop" Value="true"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate>
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="25" />
                        <RowDefinition Height="*" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>

                    <!--<Button Grid.Column="0" Grid.Row="0" x:Name="DeleteButton"
                                    Click="DeleteControlClick">Delete</Button>
                    <Button Grid.Column="1" Grid.Row="0" x:Name="AddButton"
                                    Click="AddControlClick">Add</Button>-->
                    <Button Grid.Column="0" Grid.Row="0" x:Name="DeleteButton">Delete</Button>
                    <Button Grid.Column="1" Grid.Row="0" x:Name="AddButton">Add</Button>
                    <Border 
                                Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2"
                                  Name="Border" 
                                  Background="{StaticResource WindowBackgroundBrush}"
                                  BorderBrush="{StaticResource SolidBorderBrush}"
                                  BorderThickness="1"
                                  CornerRadius="2">
                        <ScrollViewer 
                                    Margin="0"
                                    Focusable="false">
                            <StackPanel Margin="0" IsItemsHost="True" />
                        </ScrollViewer>

                        <!--<ListBox ItemTemplate="{TemplateBinding ItemTemplate}">
                            <DataTemplate>
                                <DockPanel>
                                    <TextBlock x:Name="LabelDescription" Visibility="Visible"  DockPanel.Dock="Left" Text="{Binding Description}" Height="25" Width="150" />
                                    <TextBox x:Name="EditableDescription"  DockPanel.Dock="Left" Text="{Binding Description}" Height="25" Width="150" />
                                </DockPanel>
                            </DataTemplate>
                        </ListBox>-->

                    </Border>
                </Grid>
            </ControlTemplate>

        </Setter.Value>
    </Setter>
</Style>

Вот мой класс управления

using System;
using System.Windows;
using System.Windows.Controls;

namespace TaskDash.Controls
{
[TemplatePart(Name = "Text", Type = typeof(TextBox))]
[TemplatePart(Name = "LabelText", Type = typeof(TextBlock))]
public class TextBoxWithDescription : Control
{
    static TextBoxWithDescription()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBoxWithDescription), new FrameworkPropertyMetadata(typeof(TextBoxWithDescription)));
    }

    public TextBoxWithDescription()
    {
        LabelText = String.Empty;
        Text = String.Empty;
    }

    public static readonly DependencyProperty LabelTextProperty =
        DependencyProperty.Register("LabelText", typeof(string), typeof(TextBoxWithDescription),
        new PropertyMetadata(string.Empty, OnLabelTextPropertyChanged));
    private static void OnLabelTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {

    }
    public string LabelText
    {
        get { return GetValue(LabelTextProperty).ToString(); ; }
        set { SetValue(LabelTextProperty, value); }
    }

    // http://xamlcoder.com/cs/blogs/joe/archive/2007/12/13/building-custom-template-able-wpf-controls.aspx
    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(string), typeof(TextBoxWithDescription),
        new UIPropertyMetadata(null,
                                new PropertyChangedCallback(OnTextChanged)
                           ));
    private static void OnTextChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        TextBoxWithDescription textBox = o as TextBoxWithDescription;
        if (textBox != null)
            textBox.OnTextChanged((String)e.OldValue, (String)e.NewValue);
    }
    protected virtual void OnTextChanged(String oldValue, String newValue)
    {
        // fire text changed event
        this.Text = newValue;
        this.RaiseEvent(new RoutedEventArgs(TextChangedEvent, this));
    }
    public string Text
    {
        get { return GetValue(TextProperty).ToString(); }
        set { SetValue(TextProperty, value); }
    }
    public static readonly RoutedEvent TextChangedEvent =
        EventManager.RegisterRoutedEvent("TextChanged",
                                RoutingStrategy.Bubble,
                                typeof(RoutedEventHandler),
                                typeof(TextBoxWithDescription));
    public event RoutedEventHandler TextChanged
    {
        add { AddHandler(TextChangedEvent, value); }
        remove { RemoveHandler(TextChangedEvent, value); }
    }



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

        //var textBlock = (TextBlock)this.Template.FindName("LabelText", this);
        //if (textBlock != null) textBlock.Text = this.LabelText;


        //var textBox = (TextBox)this.Template.FindName("Text", this);
        //if (textBox != null) textBox.Text = this.Text;
    }
}
}

1 Ответ

1 голос
/ 13 августа 2011

Я бы создал класс для TODO со свойствами: String Desc, Visibility txtBox, Visibility txtBlock.Тогда источником элементов для TaskDashControls является List TODO.В xaml вы можете связать свойство visibilty.В классе TODO вы можете контролировать, когда один виден, другой нет.

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