WPF列表框自定义控件问题

本文关键字:问题 自定义控件 列表 WPF | 更新日期: 2023-09-27 18:05:20

在WPF中,我正在为我的TODO程序创建一个简单的自定义控件。它应该做以下事情:

  • 显示为列表框,上面有一个添加和删除按钮。
  • 添加和删除按钮应该从我的基类中添加和删除项目。
    • 我有这个工作
  • 按下F2,我想让列表框项变成TextBox控件。

我的主要问题是:

  • 在OnKeyDown上,我得到错误:此操作仅对应用此模板的元素有效。如何解决这个问题?这是我想按F2,并能够使文本框可见和标签不可见。
  • 有更好的方法吗?如果我的控件是一个容器按钮和文本框,我不应该从ListBox继承吗?我应该继承控件,而不是使它成为一个容器吗?

    • 如果是,我如何实现它?我基本上在样式中使用以下代码,并删除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;
    }
}
}

WPF列表框自定义控件问题

我将创建一个TODO类的属性:字符串Desc,可视性txtBox,可视性txtBlock。然后TaskDashControls的项目源是TODO列表。在xaml中,您可以绑定可见性属性。在TODO类中,您可以控制当一个可见时另一个不可见。