【问题标题】:Binding not working when set from ParentControl to UserControl从 ParentControl 设置为 UserControl 时绑定不起作用
【发布时间】:2025-12-05 10:50:02
【问题描述】:

我有一个带有 UserControl 的 MainWindow。

MainWindow 绑定到一个 ViewModel,即它的 DataContext。

现在使用 MainWindowViewModel,我想在 UserControl 中绑定某些控件。

对于我要绑定的每个元素,UserControl 都有一个 DependencyProperty。

我正在从 MainWindow 将 UserControl 的 DependencyProperties 绑定到 MainWindowViewModel,但绑定不起作用。

主窗口 XAML:

<Grid >       
    <userControls:MultiSelectEnvironmentContextControl  EnvironmentVersions="{Binding EnvironmentVersions}"  x:Name="MultiSelectEnvironmentContextControl" Margin="10"  />       

</Grid>

用户控件 XAML:

    <ComboBox Grid.Column="0" Grid.Row="0" x:Name="ComboBoxVersions"  SelectedIndex="0" Margin="10" ItemsSource="{Binding EnvironmentVersions}">
       <ComboBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Version " />
                    <TextBlock Text="{Binding}" />
                </StackPanel>
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox> 

UserControl 后面的代码:

public partial class MultiSelectEnvironmentContextControl 
{        
    public MultiSelectEnvironmentContextControl()
    {
        InitializeComponent();
        this.DataContext = this;
    }

    public IEnumerable<string> EnvironmentVersions
    {
        get { return (IEnumerable<string>)GetValue(EnvironmentVersionsProperty); }
        set { SetValue(EnvironmentVersionsProperty, value); }
    }

    // Using a DependencyProperty as the backing store for EnvironmentVersions.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty EnvironmentVersionsProperty =
        DependencyProperty.Register("EnvironmentVersions", typeof(IEnumerable<string>), typeof(MultiSelectEnvironmentContextControl), new PropertyMetadata(default(IEnumerable<string>)));


}

主窗口视图模型:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using Geico.Applications.Business.CoverageTestHarness.DomainLayer;

namespace Geico.Applications.Business.CoverageTestHarness.UIWPF.ViewModels
{
    class TestRunnerControlViewModel: ViewModelBase
    {

        private DomainFacade domainFacade;


        /// <summary>
        /// Initializes a new instance of the <see cref="TestRunnerControlViewModel"/> class.
        /// </summary>
        public TestRunnerControlViewModel()
        {
            domainFacade = ((App) Application.Current).DomainFacade;
        }

        /// <summary>
        /// Gets the environment versions.
        /// </summary>
        /// <value>
        /// The environment versions.
        /// </value>
        public IEnumerable<string> EnvironmentVersions
        {
            get
            {
                return domainFacade.GetEnvironmentVersions();
            }
        }
    }
}

【问题讨论】:

  • 输出中有哪些绑定错误?
  • @netaholic 我在输出窗口中看不到任何错误。只是数据没有来,应该在绑定之后来。
  • 您的 ViewModel 类是私有的。公开
  • @netaholic 这是内部的,现在公开。结果相同。看不到任何数据。
  • 你能做一个简单的项目来说明这个问题吗?只需 1 个依赖属性、用户控件、主窗口、视图模型和测试数据,无需使用 3rd 方库。

标签: c# wpf xaml binding


【解决方案1】:

您的错误是在 usercontrol 构造函数中设置了 datacontect。 只需删除

this.DataContext = this;

public void MultiSelectEnvironmentContextControl ()
{
    ...
}

这是我的代码: MainWindow.xaml

<Window x:Class="WpfApplication8.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525" xmlns:userControls="clr-namespace:WpfApplication8">
<Grid >
    <userControls:UserControl1  EnvironmentVersions="{Binding EnvironmentVersions}"  x:Name="MultiSelectEnvironmentContextControl" Margin="10"  />

</Grid>

MainWindow.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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;

namespace WpfApplication8
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.DataContext = new TestRunnerControlViewModel();
            InitializeComponent();

        }
    }
}

UserControl.cs

  using System.Windows.Media.Imaging;
  using System.Windows.Navigation;
  using System.Windows.Shapes;

  namespace WpfApplication8
  {
    /// <summary>
    /// Interaction logic for UserControl1.xaml
    /// </summary>
    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }
    public IEnumerable<string> EnvironmentVersions
    {
        get { return (IEnumerable<string>)GetValue(EnvironmentVersionsProperty); }
        set { SetValue(EnvironmentVersionsProperty, value); }
    }

    // Using a DependencyProperty as the backing store for EnvironmentVersions.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty EnvironmentVersionsProperty =
        DependencyProperty.Register("EnvironmentVersions", typeof(IEnumerable<string>), typeof(UserControl1), new PropertyMetadata(default(IEnumerable<string>)));
    }
}

vm.cs

  using System;
  using System.Collections.Generic;
  using System.Collections.ObjectModel;
  using System.Linq;
  using System.Windows;

  namespace WpfApplication8
  {
    class TestRunnerControlViewModel 
    {
        //  private DomainFacade domainFacade;
        public TestRunnerControlViewModel()
        {
            //domainFacade = ((App)Application.Current).DomainFacade;
        }

        public IEnumerable<string> EnvironmentVersions
        {
            get
            {
                return new List<string>() { "test", "test2" };
            }
        }
    }
  }

【讨论】:

  • 好吧,我在 usercontrol 中设置了 DataContext,因为我想将控件绑定到 Dependecy Properties,如果我们不这样做,我认为它正在工作,因为作为 MainWindow 的父级的 DataContext 正在从 UserControl 访问,这不是使其工作的正确方法。
  • " 我认为它正在工作,因为正在从 UserControl 访问作为 MainWindow 的父级的 DataContext" 就是这样。你为什么要反对?它的预期行为
  • 如果你想将用户控件的属性绑定到另一个控件属性,你应该在绑定中指定sourceelement
  • 在这种情况下,我们不需要用户控件上的 DP。最初我也做了你所做的,即只使用父级的 DataContext 进行绑定,但我的代码审查被拒绝了。给我的原因是这不是推荐的做法,因为它会导致 UserControl 和 Parent 之间的耦合。正确的做法是使用 ParetCntrol 中的 Bind 到 UserControl 中的 DP
  • 那么你想将用户控件绑定到它自己的值,但是在父控件中设置绑定还是什么?根据您的代码,您希望提供给用户控件的值存储在视图模型中。那么如何不链接父母和孩子呢?