有人可以解释为什么在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); }
}
}
}