c# - WPF ListBox 自定义控件问题

标签 c# wpf xaml controls

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

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

我的主要问题/问题是:

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

    • 如果是这样,我如何实现它?我是否主要在样式中使用以下代码,并删除 OnKeyDown 等覆盖,而是为文本框注册 KeyDown 事件?我会在这篇文章后尝试一下,但如果您有任何建议,请告诉我。

我之前有一些接近的工作,在下面的代码中,但现在我希望它从我的主 Window 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;
    }
}
}

最佳答案

我将为 TODO 创建一个类,其属性为:String Desc、Visibility txtBox、Visibility txtBlock。然后 TaskDashControls 的项目源是 List TODO。在 xaml 中,您可以绑定(bind)可见性属性。在 TODO 类中,您可以控制一个可见时另一个不可见。

关于c# - WPF ListBox 自定义控件问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7047884/

相关文章:

c# - 如何将枢轴标题文本保持在屏幕中央?

javascript - CryptoJS 解密 C# DES 加密文件失败

c# - 无效操作异常 : This operation cannot be performed while an auto-filled column is being resized

c# - 更改文本 block 中部分文本的颜色

c# - 是否可以在 linq to Entity Framework 中选择一个字符串?

使用两个任意点之间的 ArcSegment 计算半圆的 WPF 数学

wpf - 为什么 WPF/RotateTransform 使用如此多的 CPU?

c# - WPF 与 XNA 渲染数千个 Sprite

c# - WPF - 在 Extended WPF Toolkit 中自定义 MessageBox 的样式

c# - 如何从具有多个路径的 svg 图像创建 appbar 按钮 PathIcon?