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属性。我错过了什么?

WPF绑定失败:双绑定解析

绑定的{Binding Port}

<dss.communication.ui:ComPortUI TargetPort="{Binding Port}"/>

是指由ComPortUI对象的DataContext属性提供的对象的属性Port

查看ComPortUI的构造函数。在这里,您将 comporti 对象的DataContext设置为IComPort实例:

DataContext = TargetPort;

因此,错误消息正确地抱怨它找不到存储在DataContext(它是派生自IComPort的对象)中的对象的Port属性。

解决方案应该很简单:不要在ComPortUI类中设置DataContext