【问题标题】:WPF binding UserControl to MainWindow as parent is failedWPF 将 UserControl 作为父级绑定到 MainWindow 失败
【发布时间】:2015-05-06 15:28:45
【问题描述】:

我是 XAML 数据绑定的新手,我陷入了这种情况。我正在使用 Mahapps MetroWindow。

假设我有一个名为 usrctrl_Camera_Control 的用户控件。我有一个简单的按钮。 C#代码如下。

namespace TA141501005
{
public partial class usrctrl_Camera_Control : UserControl
{      
    public usrctrl_Camera_Control()
    {        
        this.DataContext = this;
        InitializeComponent();
    }
}

XAML 如下所示

<UserControl
         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" 
         xmlns:Custom="http://metro.mahapps.com/winfx/xaml/controls" xmlns:local="clr-namespace:TA141501005" x:Class="TA141501005.usrctrl_Camera_Control"
         mc:Ignorable="d" 
         d:DesignHeight="768" d:DesignWidth="1366" Background="#FF2B2B2B" Height="738" Width="1336">
<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/Resources/Icons.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</UserControl.Resources>
<Grid>     
    <Button x:Name="btn_Test" Content="Button" Grid.Column="1" HorizontalAlignment="Left" Margin="472,59,0,0" VerticalAlignment="Top" Width="75" Grid.RowSpan="2" IsEnabled="{Binding Path=IsNyetEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}" />
</Grid>

MainWindow 的 C# 代码如下。

namespace TA141501005
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>

public partial class MainWindow : MetroWindow
{
    usrctrl_Camera_Control usrctrl_camera_control;
    public bool IsNyetEnabled { get; set; }
    public MainWindow()
    {
        IsNyetEnabled = false;            
        this.DataContext = this;
        InitializeComponent();      
        usrctrl_camera_control = new usrctrl_Camera_Control();
    }
}

}

MainWindow 的 XAML 代码如下所示。

    <Controls:MetroWindow x:Class="TA141501005.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
    Title="Macromium System Control V1.0ES - TA141501005 [Engineering Sample]" Height="768" Width="1366" Background="#FF2B2B2B" ScrollViewer.VerticalScrollBarVisibility="Disabled" ResizeMode="NoResize" WindowStyle="ThreeDBorderWindow" WindowStartupLocation="CenterScreen" IsMinButtonEnabled="False" IsWindowDraggable="False" ShowMaxRestoreButton="False" ShowMinButton="False" ShowSystemMenuOnRightClick="False" IconOverlayBehavior="Flyouts">
<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/Resources/Icons.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Window.Resources>

<Grid>
    <Button x:Name="btn_test" Content="Button" HorizontalAlignment="Left" Margin="589,590,0,0" VerticalAlignment="Top" Width="75" IsEnabled="{Binding IsNyetEnabled}"/>
</Grid>

我想将 usrctrl_Camera_Control 中的 btn_test 和 MainWindow 中的 btn_test 中的属性 IsEnabled 绑定到 MainWindow 中的 IsNyetEnabled。在 MainWindow 中执行 InitializeComponent() 之前,我将 IsNyetEnabled 设置为 false。

MainWindow 中的 btn_test.IsEnabled 与 MainWindow 中的 IsNyetEnabled 之间的绑定完美无缺。 MainWindow 中的 btn_test 不再启用。 (我知道,如果有任何更改,我需要实现 INotifyPropertyChanged 来通知订阅者,但为了简单起见,暂时保持原样。

但是,usrctrl_Camera_Control 中的 btn_test.IsEnabled 与 MainWindow 中的 IsNyetEnabled 绑定失败。我使用了 Visual Studio“创建数据绑定”向导,但编译时总是返回错误。

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='TA141501005.MainWindow', AncestorLevel='1''. BindingExpression:Path=IsNyetEnabled; DataItem=null; target element is 'Button' (Name='btn_Test'); target property is 'IsEnabled' (type 'Boolean')

你有什么建议吗?我已经尝试了一整天没有运气。 有没有办法在不删除 this.Datacontext = this 的情况下访问父数据上下文? 期待您的建议和解释。 非常感谢。

编辑。 我通过 Flyout 显示我的 UserControl。

Window parentWindow = Window.GetWindow(this);
object obj = parentWindow.FindName("mainFlyout");
Flyout flyout = (Flyout) obj;  
flyout.Content = new SomeFlyOutUserControl();
flyout.IsOpen = !flyout.IsOpen;

【问题讨论】:

  • 您是否使用FrameMainWindow 中显示UserControl?请在问题中添加那段代码。
  • @AnandMurali 我正在使用浮出控件来显示我的 UserControl。窗口 parentWindow = Window.GetWindow(this);对象 obj = parentWindow.FindName("mainFlyout"); Flyout flyout = (Flyout) obj; flyout.Content = new SomeFlyOutUserControl(); flyout.IsOpen = !flyout.IsOpen;

标签: c# wpf xaml


【解决方案1】:

创建IsNyetEnabled 属性作为MainForm 的依赖属性。这是mechanism that will propagate changes in WPF

例子:

public static readonly DependencyProperty IsNyetEnabledProperty = 
    DependencyProperty.Register("IsNyetEnabled", typeof(bool), 
    typeof(MainWindow),new FrameworkPropertyMetadata(false));

public bool IsNyetEnabled
{
    get { return (bool)GetValue(MainWindow.IsNyetEnabled); }
    set { SetValue(MainWindow.IsNyetEnabled, value); }
}

你可以直接在MainWindow中绑定你的Button

虽然我们必须为 UserControl 添加一个 shim,因为 UserControl 在创建它时将无法找到祖先。 在您的 UserControl 上创建,就像 Moez 发布另一个 DependencyProperty

public static readonly DependencyProperty IsButtonEnabledProperty = 
    DependencyProperty.Register("IsButtonEnabled", typeof(bool), 
    typeof(usrctrl_Camera_Control),new FrameworkPropertyMetadata(false));

public bool IsButtonEnabled
{
    get { return (bool)GetValue(usrctrl_Camera_Control.IsButtonEnabledProperty); }
    set { SetValue(usrctrl_Camera_Control.IsButtonEnabledProperty, value); }
}

将您的UserControl 按钮IsEnabled 属性绑定到该属性。

现在作为最后一步,我们必须在您创建 UserControl 时连接两个依赖属性。

<local:usrctrl_Camera_Control x:Name="yourControl" ...Whatever else... IsButtonEnabled="{Binding Path=IsNyetEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}} />

现在应该可以了。

【讨论】:

  • 它仍然给我无效的绑定。 System.Windows.Data 错误:4:找不到与引用'RelativeSource FindAncestor,AncestorType='TA141501005.MainWindow',AncestorLevel='1''的绑定源。绑定表达式:路径=IsNyetEnabled;数据项=空;目标元素是“按钮”(名称=“btn_Test”);目标属性是“IsEnabled”(类型“布尔”)是否必须手动设置 MainWindow 的 DataContext 和 UserControl 的 DataContext?
  • 此绑定错误是否可能来自主窗口上的按钮绑定,而不是来自用户控件?您将它们都称为相同的名称,因此可能会造成混淆。在该主窗口按钮上使用相同的绑定表达式:IsEnabled="{Binding Path=IsNyetEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}},让我知道这是否有效
  • 关于DataContext:没有RelativeSource 部分,它将遍历树以找到正确的祖先,因此上下文应该处理该部分。
  • 恐怕不行。我已重命名按钮,以便它们具有不同的名称,并且我无法使绑定正常工作。我仍然收到相同的绑定错误。
  • 所以我猜会发生什么情况是,当创建/评估绑定时,您的 UserControl 上面有按钮不在树中作为您的 MainWindow 的孩子,因此仰望祖先是行不通的。一个非常不雅的解决方案是在您的 UserControl 上创建另一个 DependencyProperty 并将按钮绑定到该按钮。然后你去绑定UserControl依赖属性到MainWindowDependencyProperty。但这是我现在能想到的最好的。我会在几分钟后用该解决方案反映我的答案。
【解决方案2】:

我建议你使用DependencyProperty

 public static readonly DependencyProperty IsButtonEnabledProperty = DependencyProperty.Register(
            "IsButtonEnabled", typeof(bool), typeof(UserControl1), new PropertyMetadata(default(bool)));

        public bool IsButtonEnabled
        {
            get { return (bool)GetValue(IsButtonEnabledProperty); }
            set { SetValue(IsButtonEnabledProperty, value); }
        } 

// 这里将你的 UserControl 重命名为 Test

 <Grid>     
        <Button x:Name="btn_Test" Content="Button" Grid.Column="1" HorizontalAlignment="Left" Margin="472,59,0,0" VerticalAlignment="Top" Width="75" Grid.RowSpan="2" IsEnabled="{Binding Path=IsButtonEnabled, ElementName=Test}"}" />
    </Grid>

【讨论】:

  • @Bagus 不想访问 UserControl 中 MainWindow 的属性吗?所以 DependencyProperty 应该驻留在 MainWindow...
  • @PeterSchneider 是的,我想访问用户控件内 MainWindow 的属性(即将用户控件中的 button.IsEnabled 绑定到 MainWindow 中的 bool 属性。)
【解决方案3】:

正如@Frank J 所建议的,我修改了他的最后一步。 我在运行时创建用户控件,而不是从 XAML。因此,最后一步看起来像这样。

 usrctrl_camera_control = new usrctrl_Camera_Control();
 Binding b = new Binding("IsNyetEnabled");
 b.Source = this;
 b.Mode = BindingMode.OneWay;
 usrctrl_camera_control.SetBinding(usrctrl_Camera_Control.IsButtonEnabledProperty, b);

谢谢大家。。希望对和我有同样问题的人有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-25
    • 2015-11-29
    • 1970-01-01
    • 1970-01-01
    • 2010-11-29
    • 2015-12-30
    • 2013-02-02
    • 1970-01-01
    相关资源
    最近更新 更多