为什么需要在绑定中指定ElementName和DataContext?

时间:2019-09-26 23:31:55

标签: wpf

为使自己熟悉WPF和MVVM概念,我构建了Sudoku板的视觉表示。

我的(简化的)设置是这样的(在任何地方的视图中都没有自定义代码):

我有一个MainWindow.xaml:

<Window x:Class="Sudoku.WPF.MainWindow">
    <Window.DataContext>
        <models:MainWindowViewModel/>
    </Window.DataContext>
    <ctrl:SudokuBoard DataContext="{Binding Path=GameViewModel}"/>
</Window>

我的MainWindowViewModel:

class MainWindowViewModel
{
    public MainWindowViewModel()
    {
        IGame g = new Game(4);
        this.GameViewModel = new GameViewModel(g);
    }

    public IGameViewModel GameViewModel { get; private set; }
}

SudokuBoard是UserControl。如上所述,其DataContext设置为GameViewModelGameViewModelElements的相关部分填充在ctor中,Possibilities通过以下命令设置:

public IList<CellViewModel> Elements { get; private set; }
private bool _showPossibilities;
public bool ShowPossibilities
{
    get { return _showPossibilities; }
    set
    {
        _showPossibilities = value;
        OnPropertyChanged();
    }
}

SudokuBoard.xaml中,我有:

<ItemsControl x:Name="SudokuGrid" ItemsSource="{Binding Path=Elements}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <UniformGrid/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ContentControl Style="{StaticResource ToggleContentStyle}"
                            Content="{Binding}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Elements是在CellViewModel的构造函数中生成的GameViewModel的集合。

现在有一个问题:ToggleContentStyle中定义的我的<UserControl.Resources>

<Style x:Key="ToggleContentStyle" TargetType="{x:Type ContentControl}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding Path=DataContext.ShowPossibilities, ElementName=SudokuGrid}" Value="False">
            <Setter Property="ContentTemplate" Value="{StaticResource valueTemplate}"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding Path=DataContext.ShowPossibilities, ElementName=SudokuGrid}" Value="True">
            <Setter Property="ContentTemplate" Value="{StaticResource possibilityTemplate}" />
        </DataTrigger>
    </Style.Triggers>
</Style>

ContentTemplate都以不同的表示形式显示单个CellViewModel的其他属性)

问题1:为了获得DataContext属性,我必须显式引用ShowPossibilities。如果将其省略,那么Path=ShowPossibilities会得到一个UniformGrid,其表示为ToString()。我的假设是,这是因为样式是从CellViewModel引用的,并将其绑定设置为单个ItemTemplate。这个假设有效吗?

问题2:当我省略CellViewModel部分时,我也得到ElementName的{​​{1}}表示形式。现在我真的很困惑。为什么需要它?

2 个答案:

答案 0 :(得分:0)

  1. 当您在Binding中指定一个元素时(例如ElementName = SudokuGrid),Path必须引用该元素的任何属性。因为此元素是wpf控件,所以DataContext是它的属性之一,而ShowPossibilities不是。因此,如果仅执行Path = ShowPossibilities,则将根本找不到该路径。
  2. 如果您根本没有在Binding中指定元素,则默认为与控件关联的DataContext。如果关联的DataContext不具有ShowPossibilities属性,则将无法找到它。

PS:如果要调试wpf UI以查看运行时DataContext是什么,则可以使用Snoop之类的实用程序。

答案 1 :(得分:0)

Datacontext是一个依赖项属性,标记为继承。这意味着它是在视觉树下继承的。

绑定默认位置时,它将在数据上下文中查找源。

这是简单的情况。

假设您有一个窗口,并且其datacontext设置为WindowViewmodel,并在该窗口中粘贴了一个文本框。您将其文本绑定到FooText。这意味着文本框会在WindowViewmodel的该实例中查找FooText属性。

到目前为止,一切都很简单。

下一步...

您使用元素名称。

这就是说去看看这个元素。寻找一个财产。如果您在上方的文本框中执行了此操作,那么无论您指向哪个对象,都应该具有依赖项属性FooText。

Datacontext是依赖项属性。

当您这样做时:

   "{Binding FooProperty

这是以下简称:

   "{Binding Path=FooProperty

其中FooProperty是属性路径,而不只是属性名称。

也许值得一探究竟,但这意味着您可以使用“点符号”浏览对象图并获取对象上的属性(在对象上...)。

因此DataContext.Foo或Tag。无论如何(由于tag是控件的另一个依赖项属性)。

让我们继续讨论其他一些复杂问题。

datcontext是从可视树继承的,但是这里有一些陷阱。以来 有些东西看起来像是控件,但不是(例如datagridtextcolumn)。模板化的东西可能很棘手。项目控件是一种明显且相关的特殊情况。

对于项控件,每行中任何内容的数据上下文都是从项源呈现给它的任何项。通常,您将rowviewmodel的可观察集合绑定到该itemsource。因此,(显然)列表框或数据网格会向您显示在每一行中提供的每个rowviewmodel中的数据。

如果您随后想获取该Rowview模型中没有的属性,则需要告诉它在其他地方查找。