【问题标题】:WPF - Selector - Custom Control - SelectionChanged Event Not FiringWPF - 选择器 - 自定义控件 - SelectionChanged 事件未触发
【发布时间】:2013-04-24 20:44:45
【问题描述】:

我是自定义控件创建的新手。我已经为基于 Selector 类的新自定义控件奠定了一些基础。我的理解是我应该使用这个类,因为我需要控件来拥有一个 Items 集合和处理选择的能力。我相信更改 ItemTemplate 可能会覆盖其中的某些功能,因为我没有在控件级别或应用程序级别收到 SelectionChanged 事件。我想如果我是对的,我可以将 DataTemplate 内部放入某种 SelectionRegion XAML 标记。我没有运气找到这样的东西。在谷歌浏览了一段时间后,我准备问一下。我错过了什么?下面是 ItemTemplate 标记。谢谢你的帮助。如果你能告诉我为什么 TextBlock 中的 Text 被括在括号中,即使数据不是,我也会更加感谢。

<Setter Property="ItemTemplate">
    <Setter.Value>
        <DataTemplate>
            <Border BorderBrush="Black" BorderThickness="1">
                <TextBlock Text="{Binding}" Foreground="Black" Background="White" MinHeight="12" MinWidth="50"/>
            </Border>
        </DataTemplate>
    </Setter.Value>
</Setter>

应评论者的要求,这是迄今为止该控件的完整 XAML:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:SourceMedicalWPFCustomControlLibrary">
    <Style TargetType="{x:Type local:MultiStateSelectionGrid}">
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <WrapPanel/>
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="ItemTemplate">
            <Setter.Value>
                <DataTemplate>
                    <Border BorderBrush="Black" BorderThickness="1">
                        <TextBlock Text="{Binding Code}" Foreground="Black" Background="White" MinHeight="12" MinWidth="50" Padding="2" ToolTip="{Binding Description}"/>
                    </Border>
                </DataTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:MultiStateSelectionGrid}">
                    <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,0,0,0" Background="{TemplateBinding Background}">
                        <ContentPresenter HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,0,0,0" Content="{TemplateBinding Content}"/>
                        <ItemsPresenter/>
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

还有贫血的代码隐藏:

namespace SourceMedicalWPFCustomControlLibrary
{
    public class MultiStateSelectionGridState
    {
        public Brush Background { get; set; }
        public Brush Foreground { get; set; }
        public Brush Border { get; set; }
        public string Text { get; set; }

        public MultiStateSelectionGridState()
        {
            Background = Brushes.White;
            Foreground = Brushes.Black;
            Border = Brushes.Black;
            Text = String.Empty;
        }
    };

    public class MultiStateSelectionGrid : Selector
    {
        public static readonly DependencyProperty ContentProperty =
            DependencyProperty.Register("Content", typeof(object), typeof(MultiStateSelectionGrid),
            new FrameworkPropertyMetadata(null,
                  FrameworkPropertyMetadataOptions.AffectsRender |
                  FrameworkPropertyMetadataOptions.AffectsParentMeasure));

        public object Content
        {
            get { return (object)GetValue(ContentProperty); }
            set { SetValue(ContentProperty, value); }
        }

        public static readonly DependencyProperty StatesProperty =
            DependencyProperty.Register("States", typeof(List<MultiStateSelectionGridState>), typeof(MultiStateSelectionGrid),
            new FrameworkPropertyMetadata(new List<MultiStateSelectionGridState>(),
                FrameworkPropertyMetadataOptions.AffectsRender));

        public List<MultiStateSelectionGridState> States
        {
            get { return (List<MultiStateSelectionGridState>)GetValue(StatesProperty); }
            set { SetValue(StatesProperty, value); }
        }

        static MultiStateSelectionGrid()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiStateSelectionGrid), new FrameworkPropertyMetadata(typeof(MultiStateSelectionGrid)));
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.SelectionChanged += new SelectionChangedEventHandler(MultiStateSelectionGrid_SelectionChanged);
        }

        void MultiStateSelectionGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            MessageBox.Show("Hi");
        }
    }
}

【问题讨论】:

  • 欢迎堆栈溢出。我们需要更多详细信息,您的控件的完整 xaml 和背后的代码是什么,或者如果使用 mvvm,则查看模型?
  • 根据我对选择器类的理解,如果你从它派生,那么选择事件需要自己处理,无论是通过鼠标单击、触摸还是键盘。如果您想要一个已经实现的选择事件,请改用列表视图或列表框。 CMIIW。
  • @dnr3 那么,使用 Selector 类的意义在于它拥有所有支持选择的成员变量?这似乎有点没用。
  • @JKing 在这一点上做得很少,我认为这没有什么坏处。我将添加一个编辑。
  • @BillyD 很抱歉回复晚了,但是这就是我从选择器类中所理解的,我试图创建一个也从它派生的选择器类,但因为我必须控制选择更改事件何时触发(通过单击鼠标或 mouseleftbuttondown 等)并且厌倦了它,我决定使用 listview 作为基本控件。

标签: wpf custom-controls selector itemtemplate selectionchanged


【解决方案1】:

这就是我所做的。我使用自定义控件的应用模板功能,并为我想要的控件的选择更改事件添加一个处理程序。

这里的简单示例:

public event EventHandler<SelectionChangedEventArgs> YourControlSelectionChanged;

private void Selector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (ListSelectionChanged != null) {
        ListSelectionChanged(sender, e);
    }
}

public override void OnApplyTemplate()
{
    base.OnApplyTemplate();
    //find or declare your control here, the x:name in xaml should be YourControl
    YourControl== this.Template.FindName("YourControl", this) as YourControlType
    YourControl.SelectionChanged += ResultListBox_SelectionChanged;
}

然后您可以绑定到您在 xaml 中的自定义控件类中声明的公共事件 (YourControlSelectionChanged) 的名称。

希望这会有所帮助。

【讨论】:

  • 您似乎将其视为用户控件。我可能错了。在您的示例中, OnApplyTemplate 所在的类是 Selector。我正在寻找的是一种从 ItemTemplate 中的 TextBlock 或 Border 捕获 RoutedEvent 并将其提供给 Selector 基类的方法,以便它在告诉我在新的自定义控件类级别选择了哪个 Item 时发挥了作用。然后,在将事件发送到已发生选择更改的窗口级别之前,我可以进行所需的任何处理。
  • 顺便说一句,我确实尝试使用您的逻辑的变体来命名 ItemTemplate 中的 Border 并在那里添加一个委托。虽然找不到名字。我认为这是因为 this.Template 可能不包含资源,或者由于不存在数据而可能会丢失(还没有需要渲染的项目)。
  • 这绝对来自自定义控件。您的自定义控件派生自具有 selectionchnaged 事件的基本 Selector。我不明白为什么这个事件不会给你想要的。正如我所看到的,您只是希望在后面的代码中收到有关选择/对象更改的通知。如果您不想公开自定义控件的此事件,您仍然可以在自定义控件“代码隐藏”中使用它来处理您的控制逻辑。为什么需要文本块或边框来生成此事件?
  • 当您创建自定义控件时,通常在项目的 Themes 文件夹中有一个名为 Generic.xaml 的文件。这是您定义自定义控件“部件”的地方,也是 template.find("name") 查找控件的地方
  • 您是从 Visual Studio 内置的自定义控件模板开始的吗?
【解决方案2】:

通过阅读不同控件的一些完整代码示例,我相信我的答案是我做错了。相反,我需要在 ControlTemplate 中有一个像 ListBox 一样的 Selector 控件。那么,@JKing 的建议将帮助我到达我需要去的地方。实际问题的答案是前面提到的从使用 Selector 作为基类到在控件模板中使用选择器的变化。感谢您的帮助。

【讨论】:

  • 有道理,我很难弄清楚你想要完成什么,祝你好运。我建议盯着用于自定义控件的 Visual Studio 模板,然后研究谷歌中的一些自动完成文本框示例,他们在文本框上有过滤列表框结果的示例。
猜你喜欢
  • 1970-01-01
  • 2014-05-02
  • 2013-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-17
  • 1970-01-01
  • 2013-11-05
相关资源
最近更新 更多