【问题标题】:WPF nested data binding to control - why does it not workWPF嵌套数据绑定来控制 - 为什么它不起作用
【发布时间】:2022-04-29 04:07:56
【问题描述】:

我已经搜索了很多谷歌和 stackoverflow 来找到我的问题的答案,但没有任何运气。我找到了问题的解决方案。例如:

Data Binding to Nested Properties?

但我已经知道解决方案了。我想知道为什么 wpf 不支持控件上的嵌套/点数据绑定。

解决方案是将父控件的 DataContext 设置为父数据对象,在我的情况下,我的控制器/窗口数据上下文上的 ViewModel 属性。因此,我可以设置网格的 DataContext,如果我将 TextBox 绑定更改为仅使用 Name 属性,我的代码就可以工作。

另一种解决方案是在我的 TextBox 上显式设置 UpdateSourceTrigger 并将我的嵌套数据绑定保留在 TextBox 控件上,如下所示。

但是为什么呢?为什么在不显式设置 UpdateSourceTrigger 的情况下,WPF 不支持嵌套绑定,就像我在下面所做的那样?我想知道:)。

我有这个文本框控件:

<Window>
    <Grid>
        <StackPanel>
            <Label Content="Name" FontWeight="Bold"/>
            <TextBox x:Name="NameTextBox" Text="{Binding Path=CreateEditAssetViewModel.Name, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" Width="475" Height="23" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalContentAlignment="Stretch" Margin="0, 5" />
        </StackPanel>
    </Grid>
</Window>

我的窗口数据上下文是这样绑定的:

var createEditWindow = new CreateEditWindow();
var createEditController = new CreateEditWindowController();
createEditWindow.DataContext = createEditController;
createEditWindow.Show();

我的控制器如下所示:

public class CreateEditWindowController : ViewModelBase, ICreateEditWindowController
{
    private ICreateEditWindowViewModel _createEditWindowViewModel;
    public ICreateEditWindowViewModel CreateEditAssetViewModel
    {
        get { return _createEditWindowViewModel; }
        set
        {
            if (_createEditWindowViewModel == value) return;
            _createEditWindowViewModel = value;
            OnPropertyChanged(nameof(CreateEditAssetViewModel));
        }
    }
}

带有文本框控件绑定的 Name 属性的我的 ViewModel 如下所示:

public class CreateEditWindowViewModel : ViewModelBase, ICreateEditWindowViewModel
{

    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            if (_name == value) return;
            _name = value;
            OnPropertyChanged(nameof(Name));
        }
    }
}

还有我的 ViewModelBase:

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

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

【问题讨论】:

  • 请看你提到的链接。

标签: c# .net wpf data-binding


【解决方案1】:

这里是https://msdn.microsoft.com/en-us/library/ms752347%28v=vs.100%29.aspx

查看提供视觉反馈部分,这是一个触发器绑定属性,但他们使用了一个点属性

collection views 部分相同 -> 如何创建视图

他们在 Application 对象上使用了一个虚线属性。

在调试 GUI 时查看输出视图,如果 WPF 在数据上下文中找不到属性,它将抛出日志!

【讨论】:

  • WPF 找到属性并将属性中的数据绑定到视图,但是当我使用点属性时它不启用双向绑定
【解决方案2】:

WPF 确实支持点属性,但是是的,您始终必须指定控件数据上下文。

【讨论】:

  • 您是否有任何来自 Microsoft 的官方资源来解释这一点?我似乎找不到任何:(
【解决方案3】:

我认为 wpf 确实支持嵌套/点式数据绑定。我已经在您提到的链接中发布了答案。 在哪里

<TextBox Text="{Binding Path=MyModel.MyCounter.CurrentNumber}"/>

绑定工作正常。不在这里,但我已经做了很多示例,其中嵌套属性需要绑定到某些控件属性。事实上,WPF 必须支持这种类型的绑定,否则为单独的控件提供单独的 DataContext 将是非常困难的工作。

一些例子:

1.

<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type iDP:DataRecordCellArea}},Path=Record.DataItem.IsParentRow}" Value="true">
 <Setter Property="IsEnabled" Value="False"/>

2.

<CheckBox HorizontalAlignment="Center"
                          VerticalAlignment="Center"
                          Cursor="Arrow" 
                          IsChecked="{Binding Path=DataItem.IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type view:DeleteSubLocationsView}},Path=DataContext.ImportWizardViewModel.ContextObject.IsRQSReviewFieldChecked}">

example how nested binding work

【讨论】:

    【解决方案4】:

    在 WPF 中您必须注意的一件事是使您的属性成为“依赖属性”。这有助于通知值更改:

    C#

        public static readonly DependencyProperty SelectedNodeProperty = DependencyProperty.Register(nameof(SelectedNode), typeof(FileSystemEntry), typeof(MainWindow));
        public FileSystemEntry SelectedNode
        {
            get => (FileSystemEntry)GetValue(SelectedNodeProperty);
            set => SetValue(SelectedNodeProperty, value);
        }
    

    XAML:

    <TextBox DataContext="{Binding ElementName=MainAppWindow,Path=SelectedNode}" Text="{Binding Name,Mode=OneWay}"/>
    <TextBox Text="{Binding ElementName=MainAppWindow,Mode=OneWay,Path=SelectedNode.Name}"/>
    

    现在,如果 SelectedNode 更改值,UI 将会更新。

    我希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-16
      • 1970-01-01
      • 1970-01-01
      • 2011-01-16
      • 2016-04-10
      相关资源
      最近更新 更多