【问题标题】:data not updated properly through DataBinding (C#, .NET Framework 4.7.2)数据未通过 DataBinding 正确更新(C#、.NET Framework 4.7.2)
【发布时间】:2021-12-27 20:47:33
【问题描述】:

我正在尝试编写一个 WPF 应用程序,该应用程序在一个用户控件中接受用户输入,然后在另一个用户控件中的另一个页面上显示它。 为了在 SetupLocation 中捕获用户输入,我使用了一个 TextBox,它通过 TwoWay 绑定到 LocationSettings 对象,该对象当前只有一个属性 LocationName。 另一个 Page 包含一个名为 ShowResult 的 UserControl,它具有与 LocationSettings 对象的 OneWay 绑定。

我正在使用 .NET Framework v4.7.2 和 Visual Studio 2019。

但是:

  1. 在 SetupLocation 中输入的值永远不会显示在结果页面中(结果页面显示我在 LocationSettings 的构造函数中选择分配给 LocationName 的任何默认值)。
  2. 无论我是否按下“设置”按钮,在 SetupLocation 中输入的值都会被保留。似乎 UpdateSourceTrigger 参数被忽略了,因为当我使用 LostFocus 作为 UpdateSourceTrigger 的参数时,我得到了完全相同的结果。

我错过了什么?

这是 UserControl 的 XAML,称为 SetupLocation(用于输入数据):

<StackPanel Orientation="Vertical" Margin="10"
            VerticalAlignment="Top">
    <StackPanel.Resources>
        <ObjectDataProvider x:Key="locationInput" ObjectType="{x:Type classes:LocationSettings}"/>
    </StackPanel.Resources>
    <TextBox x:Name="LocationName" 
        <TextBox.Text>
            <Binding Source="{StaticResource locationInput}"
                     Path="LocationName"
                     Mode="TwoWay"
                     UpdateSourceTrigger="Explicit"/>
        </TextBox.Text>
    </TextBox>
    <Button x:Name="addParameters"  
            Content="Set"
            Click="addParameters_Click"/>
</StackPanel>

SetupLocation 的代码:

    public partial class SetupLocation : UserControl
    {
        public SetupLocation()
        {
            InitializeComponent();
        }

        private void addParameters_Click(object sender, RoutedEventArgs e)
        {
            BindingExpression be = LocationName.GetBindingExpression(TextBox.TextProperty);
            be.UpdateSource();
        }
    }

UserControl 的 XAML(与 SetupLocation 不同的页面的一部分)ShowResult 应该显示在 SetupLocation 中输入的内容:

<StackPanel>
    <StackPanel.Resources>
        <ObjectDataProvider x:Key="locationInput" ObjectType="{x:Type classes:LocationSettings}"/>
    </StackPanel.Resources>
    <Label FontSize="18" Foreground="Green">
        <Label.Content>
            <Binding Source="{StaticResource locationInput}"
                          Path="LocationName"
                          />
        </Label.Content>
    </Label>
</StackPanel>

包含我需要在两个用户控件之间传递的 LocationName 变量的 LocationSettings 类。

   public class LocationSettings : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private string _locationName;
        public string LocationName
        {
            get {
                return _locationName; 
            }
            set {

                _locationName = value;
                OnPropertyChanged();
            }
        }
        
        public LocationSettings()
        {
            // _locationName = "Nowhere really";

        }
        protected void OnPropertyChanged([CallerMemberName] string tmp = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(tmp));
        }
        
    }

MainWindow.xaml:

    public partial class MainWindow : Window
    {
        public LocationSettings DefaultSettings;

        public MainWindow()
        {
            InitializeComponent();
            DefaultSettings = new LocationSettings();
        }

【问题讨论】:

    标签: c# wpf data-binding


    【解决方案1】:

    你知道下面使用ObjectDataProvider 的代码是做什么的吗?它在 xaml 中创建 LocationSettings 类型的对象。由于您在两个用户控件中都执行此操作,因此您创建了 2 个对象(每个用户控件中 1 个),因此每个用户控件都绑定到不同的对象。

    <StackPanel.Resources>
        <ObjectDataProvider x:Key="locationInput" ObjectType="{x:Type classes:LocationSettings}"/>
    </StackPanel.Resources>
    

    作为一种可能的解决方案,我假设您的 MainWindow 托管两个用户控件。如果是这种情况,请将主窗口的DataContext 设置为您在构造函数中创建的LocationSettings,而不是在用户控件中使用ObjectDataProvider。父(您的MainWindow)数据上下文将由两个用户控件继承。

    public partial class MainWindow : Window
    {
        // I changed this to a "getter".
        // The way you declared it would make it a public "field" and not a "property"
        public LocationSettings DefaultSettings { get; }
    
        public MainWindow()
        {
            InitializeComponent();
            DefaultSettings = new LocationSettings();
            DataContext = DefaultSettings;  // Set the data context of the main window
        }
    

    【讨论】:

    • 您好,感谢您的指点。我对 DataContext 不是很熟悉。用户控件放置在两个单独的页面中,可以通过单击主窗口中的按钮来激活它们。然而,使用 DataContext 并没有解决问题。我想我需要使用 &lt;ObjectDataProvider x:Key="locationInput" ObjectInstance="{x:Reference classes:DefaultSettings}" 而不是 ObjectType,但这会引发异常(未解析的引用 'classes:DefaultSettings')。
    • @Raits:DataContext 是 WPF 的基本部分之一,因此我强烈建议您学习一下。 Here is a simple tutorial 让您开始。至于你的问题,我建议先让你的代码在没有单独页面的情况下工作,然后从那里慢慢构建。我想帮忙,但不幸的是,您没有显示最重要的部分,即主窗口的 xaml。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-08
    • 1970-01-01
    • 2020-09-08
    • 2014-01-09
    • 2022-12-04
    • 2020-04-04
    • 1970-01-01
    相关资源
    最近更新 更多