WPF绑定失败:双绑定解析
本文关键字:绑定 失败 WPF | 更新日期: 2023-09-27 18:15:35
我有一个用于设置串行端口的用户控件。XAML是这样的:
<UserControl x:Class="DSS.Communication.UI.ComPortUI"
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:utilUI="clr-namespace:DSS.Util.UI;assembly=DSS.Util"
xmlns:localUI="clr-namespace:DSS.Communication.UI"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<utilUI:DebugConverter x:Key="DebugConverter"/>
<localUI:BoolXIsOpenConverter x:Key="IsOpenConverter"/>
</UserControl.Resources>
<StackPanel>
<StackPanel>
<TextBlock Text="{Binding StringFormat='ComPortUI.DataContext: {0}',FallbackValue='ComPortUI.DataContext: Null'}"/>
<TextBlock Text="{Binding StringFormat='ComPortUI.TargetPort: {0}',FallbackValue='ComPortUI.TargetPort: Null',RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl},Path=TargetPort}"/>
<DockPanel>
<utilUI:IndicatorLight DockPanel.Dock="Right" Width="20" CurrentBrush="{Binding IsOpen,Converter={StaticResource IsOpenConverter}}"/>
<TextBlock DockPanel.Dock="Right" Text="{Binding PortName.FriendlyName}"/>
</DockPanel>
<StackPanel Orientation="Horizontal">
<ComboBox x:Name="UI_AvailablePorts_CB" SelectedItem="{Binding PortName, Converter={StaticResource DebugConverter}}" Width="150">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding SimpleName}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ComboBox x:Name="UI_Baudrate_CB" SelectedItem="{Binding BaudRate}" Width="150">
</ComboBox>
</StackPanel>
<Button x:Name="UI_RawComs_Btn" Click="UI_RawComs_Btn_Click" IsEnabled="{Binding IsOpen}">Monitor</Button>
</StackPanel>
</StackPanel>
后面代码的重要位是:
public IComPort TargetPort
{
get { return (IComPort)GetValue(TargetPortProperty); }
set { SetValue(TargetPortProperty, value); }
}
// Using a DependencyProperty as the backing store for TargetPort. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TargetPortProperty =
DependencyProperty.Register("TargetPort", typeof(IComPort), typeof(ComPortUI), new PropertyMetadata(null,TargetPort_Changed));
public static void TargetPort_Changed(DependencyObject d,DependencyPropertyChangedEventArgs e)
{
System.Diagnostics.Debugger.Log(0, "TargetPort_Changed",String.Format("{0}->{1}'r'n",e.OldValue,e.NewValue==null?"null":e.NewValue));
ComPortUI ui = (ComPortUI)d;
:
public ComPortUI()
{
_isMonitoring = false;
InitializeComponent();
foreach (ComPortName cpn in ComPort.AvailablePorts)
UI_AvailablePorts_CB.Items.Add(cpn);
foreach (int br in BaudRates)
{
UI_Baudrate_CB.Items.Add(br);
}
Dispatcher.BeginInvoke(new Action(() =>
{
System.Diagnostics.Debugger.Log(0, "ComPortUI()", "DataContext Changed'r'n");
DataContext = TargetPort;
}), System.Windows.Threading.DispatcherPriority.ApplicationIdle);
}
ui.DataContext = e.NewValue;
}
现在,当我像这样使用控件时:
MainWindow.cs:
public partial class MainWindow : Window {
public MainWindow() {
DataContext = new ComPort();
InitializeComponent();
}
}
public class MainWindowContext {
public MainWindowContext() {
Port = new ComPort();
}
public ComPort Port {
get;
protected set;
}
}
MainWindow.xaml:
<Window x:Class="DSSUITest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dss.communication.ui="clr-namespace:DSS.Communication.UI;assembly=DSS.Communication"
xmlns:dss.util.ui="clr-namespace:DSS.Util.UI;assembly=DSS.Util"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<dss.communication.ui:ComPortUI TargetPort="{Binding}"/>
</StackPanel>
</Window>
一切正常,但是当我这样做时:
MainWindow.cs:
public partial class MainWindow : Window {
public MainWindow() {
DataContext = new MainWindowContext()
InitializeComponent();
}
}
public class MainWindowContext {
public MainWindowContext() {
Port = new ComPort();
}
public ComPort Port {
get;
protected set;
}
}
MainWindow.xaml:
<Window x:Class="DSSUITest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dss.communication.ui="clr-namespace:DSS.Communication.UI;assembly=DSS.Communication"
xmlns:dss.util.ui="clr-namespace:DSS.Util.UI;assembly=DSS.Util"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<dss.communication.ui:ComPortUI TargetPort="{Binding Port}"/>
</StackPanel>
</Window>
我得到一个绑定错误,特别是:
System.Windows.Data Error: 40 : BindingExpression path error: 'Port' property not found on 'object' ''ComPort' (HashCode=40105335)'. BindingExpression:Path=Port; DataItem='ComPort' (HashCode=40105335); target element is 'ComPortUI' (Name=''); target property is 'TargetPort' (type 'IComPort')
这会导致TargetPort以及随后的DataContext变为null,您可能会想到这会导致一些问题。
我对此感到非常困惑,因为TargetPort属性实际上得到设置两次,第一次正确(从null到Binding),然后第二次,当…我不知道会发生什么。看起来绑定在两个不同的东西上被解析了两次,首先是MainWindowContext,然后是MainWindowContext的Port属性。我错过了什么?
绑定的{Binding Port}
<dss.communication.ui:ComPortUI TargetPort="{Binding Port}"/>
是指由ComPortUI对象的DataContext属性提供的对象的属性Port。
查看ComPortUI的构造函数。在这里,您将 comporti 对象的DataContext设置为IComPort实例:
DataContext = TargetPort;
因此,错误消息正确地抱怨它找不到存储在DataContext(它是派生自IComPort的对象)中的对象的Port属性。
解决方案应该很简单:不要在ComPortUI类中设置DataContext