【问题标题】:Binding to a dependency property of a user control WPF/XAML绑定到用户控件 WPF/XAML 的依赖项属性
【发布时间】:2011-07-22 08:08:31
【问题描述】:

我的应用如下所示:


SectionHeader

SectionHeader

内容

SectionHeader

内容


SectionHeader 是一个用户控件,具有两个依赖属性 = Title 和 Apps。

标题不变,但应用程序需要绑定到主窗口视图模型的应用程序属性。只有三个部分标题中的两个需要 Apps 属性。

<c:SectionHeader DockPanel.Dock="Top" x:Name="SectionResources" Title="RESOURCES"
   Apps="{Binding Path=Apps}" />

目前就是这样。问题是应用程序不显示。

在SectionHeader 中,DataContext 设置为自身,如下所示,允许显示标题。

DataContext="{Binding RelativeSource={RelativeSource Self}}"

Apps 是 UserControl 中 ItemsControl 的 ItemsSource:

<ItemsControl
      ItemsSource="{Binding Apps}">

所以我的问题是:

  • 如何将数据绑定到 UserControl DP?
  • 在没有 UserControls 的情况下,他们是否可以更轻松地进行此布局?

编辑:

忘了说 Apps 是 AppsItems 的 ObservableCollection。

这就是我的 DP 的样子:

public static readonly DependencyProperty AppsProperty = DependencyProperty.Register("Apps",
  typeof (ObservableCollection<AppsItem>), typeof (SectionHeader),
  new PropertyMetadata(null, OnAppsPropertyChanged));

private static void OnAppsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  Console.WriteLine("Hello!!!");
  var sectionHeader = d as SectionHeader;
  var value = e.NewValue as ObservableCollection<AppsItem>;
  sectionHeader.Apps = value;
}

【问题讨论】:

    标签: c# wpf xaml


    【解决方案1】:

    为你的 usecontrol 命名并尝试像这样绑定

    ItemsSource="{Binding Apps,ElementName=root}"
    

    root 是用户控件的名称

      <UserControl x:Class="WpfApplication1.MainWindow"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 Height="350" Width="525"
         x:Name="root">
    

    它是绑定到具有 Apps 属性的用户控件的元素

    【讨论】:

    • Title 属性绑定得很好 - Apps 属性是问题所在。请参阅问题编辑。
    • 您确定您在“Apps="{Binding Path=Apps}" 中绑定的 Apps 属性与您的依赖项属性类型相同,即 ObservableCollection 。确保您没有绑定像 List 或 IEnumerable.. 它应该是 ObservableCollection 类型
    • 它起作用了,但我没有找到不早点起作用的原因:/ 我在用户控件中有 4 个属性。但其中两个正在工作。有了这个,它开始工作了..但我很好奇为什么它没有:/
    【解决方案2】:

    试图从您的描述中重现这一点并遇到类似的问题,我发现我可以让它工作的唯一方法是不设置 UserControl 的 DataContext,而是使用 ElementBinding:

    <UserControl x:Class="WpfApplication2.UserControl1"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 mc:Ignorable="d" 
                 x:Name="thisUC"
                 d:DesignHeight="300" d:DesignWidth="300">
        <Grid>
            <Border Background="Red" Padding="10">
            <ListBox x:Name="ucList" ItemsSource="{Binding ElementName=thisUC, Path=UCApps}"/>
            </Border>
    
        </Grid>
    </UserControl>
    

    这个 UC 的实现非常简单:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Collections.ObjectModel;
    using System.Collections;
    
    namespace WpfApplication2
    {
        /// <summary>
        /// Interaction logic for UserControl1.xaml
        /// </summary>
        public partial class UserControl1 : UserControl
        {
            public IEnumerable UCApps
            {
                get { return (IEnumerable)GetValue(UCAppsProperty); }
                set { SetValue(UCAppsProperty, value); }
            }
    
            // Using a DependencyProperty as the backing store for Apps.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty UCAppsProperty =
                DependencyProperty.Register("UCApps", typeof(IEnumerable), typeof(UserControl1), new UIPropertyMetadata(null));
    
            public UserControl1()
            {
                InitializeComponent();            
            }
        }
    }
    

    调用它的 XAML 也是如此:

    <Grid >
        <my:UserControl1 x:Name="ucName" UCApps="{Binding Path=Apps}"/>
    </Grid>
    

    (我在你的用户控件中将Apps 的名称更改为UCApps,这样我就可以看到发生了什么——太多同名的属性会让人感到困惑!)

    【讨论】:

    • 嗨,马克,感谢您的帮助。这个建议与上面的 Bathineni 类似,用户控件名为 root。这是我最终需要做的——但我试图绑定的集合也存在问题。
    【解决方案3】:
    Apps="{Binding Path=Apps}"
    

    将应用程序绑定到自身。

    尝试关注

    1) 你的 ViewModel 应该是 Control 的 DataContext,那么你可以使用以下

    Apps="{Binding DataContext.Apps}"
    

    您还可以使用Snoop 实用程序实时查找绑定问题

    【讨论】:

    • 似乎没有修复它。 UserControl 中的 Apps DP 的 Setter 未被触发。
    • @reckoner:setter 不会被触发,而是由框架调用 Get 和 Set 方法。如果您需要对更改的依赖项属性做出反应,则需要添加回调。
    • @reckoner:这就是为什么建议不要在 DP 的 getter 和 setter 中放置任何逻辑,因为 WPF 以其他方式调用 DP
    • 谢谢 sll,我认为它更多地与 MainWindow 和 UserControl 之间的交互有关。请参阅问题编辑,因为我忽略了 Apps 是 ObservableCollection 的事实。
    【解决方案4】:

    你试过了吗

    Apps="{Binding Apps}" 
    

    而不是

    Apps="{Binding Path=Apps}"
    

    在您的顶级控件中?

    另外,当您运行应用程序时,您是否在 VS 输出窗口中遇到任何绑定错误?

    【讨论】:

    • 无绑定错误。 Apps vs. Path=Apps 没有区别。奇怪的是,我的 Console.WriteLine(..) 在放入 Title getter 和 setter 时不会触发。
    猜你喜欢
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2013-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多