绑定到DataGrid单元中的UserControl:BindingExpression路径错误

时间:2018-12-30 18:38:16

标签: wpf data-binding

有人可以解释为什么在ListBox(在MainWindow.xaml中)上的绑定起作用而在DataGrid中对local:QtyControl(UserControl)进行的相同技术不起作用吗?

我得到的错误是:

  

System.Windows.Data错误:40:BindingExpression路径错误:在“对象”“ QtyControl”(名称=“)”上找不到“ QtyRequested”属性。 BindingExpression:Path = QtyRequested; DataItem ='QtyControl'(Name ='');目标元素是'QtyControl'(Name ='');目标属性为“数量”(类型为“ Int32”)

让我特别困惑的是,为什么当我尝试绑定到MyViewModel的那个属性时,它认为我试图绑定到QtyControl的QtyRequested属性。

我的目标是在ComboBox中设置一个值,单击“添加”按钮,然后让MessageBox告诉我选择了哪个值。

MainWindow.xaml:

<Window x:Class="UserControlTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:UserControlTest"
        Title="MainWindow" Height="150" Width="250">
  <StackPanel>
    <ListBox ItemsSource="{Binding MyItems}">
      <ListBox.ItemTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding QtyRequested}" />
        </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>

    <DataGrid ItemsSource="{Binding MyItems}"
              IsReadOnly="True"
              Height="Auto" Width="Auto"
              HeadersVisibility="Column"
              AutoGenerateColumns="False"
              SelectionMode="Single">
      <DataGrid.Columns>
        <DataGridTemplateColumn Header="Qty" Width="50">
          <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
              <local:QtyControl Qty="{Binding QtyRequested, Mode=TwoWay}" QtyChanged="QtyControl_QtyChanged" />
            </DataTemplate>
          </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn Header="Add" Width="50">
          <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
              <Button Click="_AddItemBtn_Click">Add</Button>
            </DataTemplate>
          </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
      </DataGrid.Columns>
    </DataGrid>
  </StackPanel>
</Window>

MainWindow.xaml.cs:

using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

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

        private void _AddItemBtn_Click(object sender, RoutedEventArgs e)
        {
            DataGridRow parentRow = _FindDataGridRowFromCl((Control)sender);
            MyItem item = (MyItem)parentRow.Item;
            MessageBox.Show($"QtyRequested = {item.QtyRequested}");
        }

        private DataGridRow _FindDataGridRowFromCl(Control cl)
        {
            for (Visual vi = cl as Visual; vi != null; vi = VisualTreeHelper.GetParent(vi) as Visual)
                if (vi is DataGridRow row)
                    return row;
            return null;
        }

        private void QtyControl_QtyChanged(object sender, RoutedPropertyChangedEventArgs<int> e)
        {

        }
    }

    public class MyItem
    {
        public int QtyRequested { get; set; } = 0;
    }

    public class MyViewModel : INotifyPropertyChanged
    {
        private List<MyItem> _myItems;
        public List<MyItem> MyItems {
            get {
                return _myItems;
            }
            set {
                _myItems = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MyItems)));
            }
        }

        public MyViewModel()
        {
            MyItems = new List<MyItem> { new MyItem() };
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

QtyControl.xaml:

<UserControl x:Class="UserControlTest.QtyControl"
             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:local="clr-namespace:UserControlTest"
             mc:Ignorable="d" Height="22" Width="42"
             DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}">
  <Grid>
    <ComboBox Name="_comboBox"
              SelectedIndex="{Binding Qty}">
      <ComboBox.Items>
        <ComboBoxItem Content="0" IsSelected="True" />
        <ComboBoxItem Content="1" />
        <ComboBoxItem Content="2" />
      </ComboBox.Items>
    </ComboBox>
  </Grid>
</UserControl>

QtyControl.xaml.cs:

using System.Windows;
using System.Windows.Controls;

namespace UserControlTest
{
    public partial class QtyControl : UserControl
    {
        public QtyControl()
        {
            InitializeComponent();
        }

        public static DependencyProperty QtyProperty;

        static QtyControl()
        {
            QtyProperty = DependencyProperty.Register(
                "Qty",
                typeof(int),
                typeof(QtyControl),
                new FrameworkPropertyMetadata(1, new PropertyChangedCallback(_OnQtyChanged))
                );
            QtyChangedEvent = EventManager.RegisterRoutedEvent(
                "QtyChanged",
                RoutingStrategy.Bubble,
                typeof(RoutedPropertyChangedEventHandler<int>),
                typeof(QtyControl)
                );
        }

        public int Qty
        {
            get { return (int)GetValue(QtyProperty); }
            set { SetValue(QtyProperty, value);  }
        }

        private static void _OnQtyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            QtyControl qtyControl = (QtyControl)sender;
            int newQty = (int)e.NewValue;
            qtyControl._comboBox.SelectedItem = newQty;

            int oldQty = (int)e.OldValue;
            RoutedPropertyChangedEventArgs<int> args = new RoutedPropertyChangedEventArgs<int>(oldQty, newQty)
            {
                RoutedEvent = QtyControl.QtyChangedEvent
            };
            qtyControl.RaiseEvent(args);
        }

        public static readonly RoutedEvent QtyChangedEvent;

        public event RoutedPropertyChangedEventHandler<int> QtyChanged
        {
            add { AddHandler(QtyChangedEvent, value); }
            remove { RemoveHandler(QtyChangedEvent, value); }
        }
    }
}

0 个答案:

没有答案