【问题标题】:Binding to Dependency Property which is, in turn, bound to another binding source绑定到依赖属性,该属性又绑定到另一个绑定源
【发布时间】:2011-01-13 19:55:35
【问题描述】:

这很难解释,但我会尽力而为。 我想要一个具有 3 个按钮的可重用控件,一个用于创建实体,另一个用于编辑,另一个用于删除,这是相关部分的缩写 XAML。

--

<!-- ActionButtons.xaml -->

<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top">
        <Button Name="btnNew" Content="New" Command="{Binding Path=NewCommand}" />
        <Button Name="btnEdit" Content="Edit" Command="{Binding Path=EditCommand, Mode=OneWay}" />
        <Button Name="btnDelete" Content="Delete" Command="{Binding Path=DeleteCommand, Mode=OneWay}" />
    </StackPanel>

--

然后,在后面的代码中我有 dpprops 声明:

// ActionButtons.xaml.cs

public uscActionButtons()
{
            InitializeComponent();
            this.DataContext = this;
        }

        public ICommand NewCommand
        {
            get { return (ICommand)GetValue(NewCommandProperty); }
            set { SetValue(NewCommandProperty, value); }
        }

        // Using a DependencyProperty as the backing store for NewCommand.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty NewCommandProperty =
            DependencyProperty.Register("NewCommand", typeof(ICommand), typeof(uscActionButtons), new UIPropertyMetadata(null, new PropertyChangedCallback(OnCommandChanged)));

我想将 NewCommand 属性绑定到另一个控件中的特定实现。示例预期用途:

<!-- SomeControl.xaml -->
<common:uscActionButtons Grid.Row="0" HorizontalAlignment="Left" 
                                 NewCommand="{Binding NewItemCommand}"
                                 />

// SomeControlViewModel.cs
// Note: SomeControlViewModel IS in the DataContext of SomeControl.
public ICommand NewItemCommand
        {
            get
            {
                if (mNewItemCommand == null)
                {
                    mNewItemCommand = new RelayCommand(x => this.CreateItem());
                }

                return mNewItemGroupCommand;
            }
        }

问题是可重用控件 (ActionButtons) 没有看到 NewItemCommand。 如果我使用一个简单的按钮,它看起来很好。似乎问题在于这种“链式”绑定。 但我知道这是可能的,WPF 按钮有一个 Command 依赖属性,您可以将命令绑定到该属性,因此创建我自己的可重用控件并公开 ICommand 依赖属性一定不难。

有什么想法吗?

谢谢


编辑:这是解决方案,我所要做的就是将 RelativeSource 与 FindAncestor 一起使用。

<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top">
        <Button Name="btnNew" Content="New" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:uscActionButtons}, Path=NewCommand, Mode=OneWay}" />
        <Button Name="btnEdit" Content="Edit" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:uscActionButtons}, Path=EditCommand, Mode=OneWay}" />
        <Button Name="btnDelete" Content="Delete" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:uscActionButtons}, Path=DeleteCommand, Mode=OneWay}" />
    </StackPanel>

【问题讨论】:

    标签: c# .net wpf data-binding command


    【解决方案1】:

    您看到的问题是您正在更改ActionButtons 控件的DataContext。当您在构造函数中设置其DataContext 时,您在其上指定的所有Bindings(甚至来自实例化它的外部XAML)都将指向新的DataContext。因此,当您在SomeControl 中应用Binding 时,该绑定试图绑定DataContext,而这恰好是ActionButtons 实例。

    我认为Control 不应该设置自己的DataContext,因为它会导致您看到的错误。如果你想使用UserControl(我自己可能会使用Control,这样我就可以使用TemplateBindings),那么你可以使用RelativeSource绑定(正如你在对Snowbear的评论中提到的那样), Bindings 应该可以工作。

    【讨论】:

    • 我改为RelativeSource(我确信我已经尝试过),至少现在它调用了SomeControlViewModel.cs上NewItemCommand属性的GET,不幸的是它没有调用注入RelayCommand的构造函数的委托(RelayCommand 已经被广泛使用,所以我确信它很好)。有任何想法吗?已经删除了“this.DataContext = this”,你说服了我使用它的缺点:)
    【解决方案2】:

    这是我的代码中缺少的内容:

    <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top">
            <Button Name="btnNew" Content="New" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:uscActionButtons}, Path=NewCommand, Mode=OneWay}" />
            <Button Name="btnEdit" Content="Edit" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:uscActionButtons}, Path=EditCommand, Mode=OneWay}" />
            <Button Name="btnDelete" Content="Delete" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:uscActionButtons}, Path=DeleteCommand, Mode=OneWay}" />
        </StackPanel>
    

    我不得不将 RelativeSource 与 FindAncestor 一起使用。

    感谢您的所有回答!

    【讨论】:

      【解决方案3】:
      this.DataContext = this;
      

      这似乎是个问题,因为在这个 XAML 中:

       NewCommand="{Binding NewItemCommand}"
      

      您正在绑定到 ActionButtons 本身的 NewItemCommand。这就是为什么我认为在控件内部设置 self DataContext 是不好的模式。如果您确实需要此 DataContext(您是否需要),请将其设置为您的顶级内部元素(在您的情况下为 StackPanel)

      Visual Studio 调试器也应该在这里帮助您调试绑定。如果您将在附加调试器的情况下运行您的应用程序,那么在 Visual Studio 的输出窗口中,您将看到绑定错误,它们通常很容易理解,该错误会让您知道,对于此特定绑定,它会在 ActionButtons 实例中查找 NewItemCommand 属性,而不是你期待的课程。

      更新 在 VS 中测试了您的代码。输出窗口中的错误:

      System.Windows.Data Error: 40 : BindingExpression path error: 'NewItemCommand' property not found on 'object' ''uscActionButtons' (Name='')'. BindingExpression:Path=NewItemCommand; DataItem='uscActionButtons' (Name=''); target element is 'uscActionButtons' (Name=''); target property is 'NewCommand' (type 'ICommand')
      System.Windows.Data Error: 40 : BindingExpression path error: 'EditCommand' property not found on 'object' ''uscActionButtons' (Name='')'. BindingExpression:Path=EditCommand; DataItem='uscActionButtons' (Name=''); target element is 'Button' (Name='btnEdit'); target property is 'Command' (type 'ICommand')
      System.Windows.Data Error: 40 : BindingExpression path error: 'DeleteCommand' property not found on 'object' ''uscActionButtons' (Name='')'. BindingExpression:Path=DeleteCommand; DataItem='uscActionButtons' (Name=''); target element is 'Button' (Name='btnDelete'); target property is 'Command' (type 'ICommand')
      

      您是否会因为打开输出窗口太晚而错过这些错误?

      更新 2:

      修复了替换你的:

      this.DataContext = this;
      

      和我的:

      root.DataContext = this; //root - name for stackpanel
      

      【讨论】:

      • 您正在混合两种不同的控件。 NewCommand 属性在 ActionButtons 中,NewItemCommand 在 SomeControl 中。我做了“this.DataContext = this”将“new”按钮的Command属性绑定到“NewCommand”属性。或者,我可以使用RelativeSource 或ElementName 并为ActionButtons 命名,但它对我来说或多或少是相同的。 VS 调试器指示没有绑定错误。注意:一切的数据上下文都在它需要的地方。
      • 更新了我的答案,用 cmets 回复是地狱:(
      • 我根据 Abe Heidebrecht 的评论删除了“this.DataContext = this”,现在它在 SomeControlViewModel.cs 上调用 NewItemCommand 属性上的 GET,但当我单击按钮时不调用执行委托:(
      • 在您的第一个代码块中,您有:“Binding Path=NewCommand”。也许这个逗号引起了一些问题?
      猜你喜欢
      • 2016-01-22
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      • 2018-05-21
      • 1970-01-01
      • 2012-08-26
      • 2011-12-26
      • 1970-01-01
      相关资源
      最近更新 更多