【问题标题】:How to make available in a usercontrol a inner control collection in Wpf?如何在用户控件中使 Wpf 中的内部控件集合可用?
【发布时间】:2025-11-29 02:55:02
【问题描述】:

我有一个 WPF UserControl 包装了一些其他控件。其中之一是ItemsControl,我需要在ItemsControlItems 属性中提供UserControl,所以我做了以下操作:

public partial class MyControl : UserControl
{
    private static readonly DependencyPropertyKey PagesPropertyKey = DependencyProperty.RegisterReadOnly("Pages", typeof(ObservableCollection<XXX>), typeof(MyControl), new FrameworkPropertyMetadata(new ObservableCollection<XXX>()));

    public static DependencyProperty PagesProperty = PagesPropertyKey.DependencyProperty;

    public ObservableCollection<XXX> Pages
    {
        get { return (ObservableCollection<XXX>) base.GetValue(PagesProperty); }
        set { base.SetValue(PagesProperty, value); }
    }
}

然后在 XAML 中 ItemsControl 具有以下内容:

ItemsSource="{Binding Pages, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:TypeExtension views1:MyControl}}}"

我认为这应该可以工作,实际上使用 Snoop 查找 UserControlItemsControl 具有相同的元素,但是当我直接将元素添加到内部 ItemsControl 时,我添加的第一个元素会自动选择,当我使用我的UserControl 执行此操作没有发生任何选择,所以出了点问题。

有什么想法吗?

编辑:该控件是一个向导控件,因为我们总是将它与周围的一些其他控件一起使用,所以我正在创建一个新的用户控件。如果我在 View 中直接使用 Wizard 自动选择 ItemsSource gest 的第一项,如果我将 Wizard 的 ItemsSource 设置为 Pages 属性,则启动时没有选择页面。

我真的很想知道为什么会这样。

【问题讨论】:

  • 您可以选择从ItemsControl 派生而不仅仅是UserControl
  • @Vignesh.N:我有几个控件要显示,它们不是 ItemsControl 的一部分。 ItemsControl 会尝试像 ListBox 一样绘制所有内容,不是吗?

标签: c# wpf data-binding binding user-controls


【解决方案1】:

如果您的自定义控件只是一个 ItemsControl,您可以从 ItemsControl 派生而不是 UserControl

此外,您在使用 UserControl 时看不到被选中的项目,因为在初始化期间发生绑定时,默认值为空集合/null,因此在初始化控制。 稍后,一旦 Pages 属性获得其值,您需要设置 SelectedItemUserControl

FrameworkPropertyMetadata 有另一个构造函数,您可以在其中指定PropretyChangedEventHandler,您可以在其中设置SelectedItemSelectedIndex

public partial class MyControl : UserControl
{
    private static readonly DependencyPropertyKey PagesPropertyKey = DependencyProperty.RegisterReadOnly("Pages", typeof(ObservableCollection<XXX>), typeof(MyControl), new FrameworkPropertyMetadata(null,OnPagesChanged));

    public static DependencyProperty PagesProperty = PagesPropertyKey.DependencyProperty;

    public ObservableCollection<XXX> Pages
    {
        get { return (ObservableCollection<XXX>) base.GetValue(PagesProperty); }
        set { base.SetValue(PagesProperty, value); }
    }
}

        private static void OnPagesChanged(DependencyObject o, DependencyPropertyChangedEventArgs args)
        {
//play with DepedencyObject here; cast it to type MyControl and assign/change instance variables
//Raise some events which can be bubbled.
//Set SelectedIndex here
        }

【讨论】:

  • 是的,我可以这样做,但真正的问题是为什么行为会发生变化...¿?
  • 您的控件是否还有SelectedItem 属性? ItemsControl 将具有SelectedItem 属性,并且每当ItemsSource 更改时,控件都会更改SelectedItem(设置为第一个)。同样,您有 Pages 属性,可能需要 SelectedPage 并将其设置为当前未完成的值。
【解决方案2】:

我解决了它用构造函数调用替换 ItemsSource 绑定:

this.ItemsControlInnerControl.ItemsSource = this.Pages;

不知道为什么会这样,并且绑定不起作用...无论如何...

【讨论】: