无法在资源字典中绑定

7

我正在运行一个简单的MVVM项目,但在第一关卡就失败了。我使用Josh Smith的Relay Command方法绑定命令。

问题是,当按钮位于ResourceDictionary中时,它无法绑定。如果将代码(完全相同)移动到我的MainWindow.xaml文件中,代码将按预期执行。

这是我的MainWindow.xaml文件:

<Window x:Class="ForJon.Views.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:ForJon.Ui.ViewModels"
    Title="MainWindow" Height="350" Width="525">
   <Grid>

    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="160" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>

   <Grid.Resources>
        <ResourceDictionary Source="Resources\ResourceDictionary.xaml" />
    </Grid.Resources>

    <Grid.DataContext>
        <vm:MainWindowViewModel />
    </Grid.DataContext>

    <HeaderedContentControl
        Header="Options"
        Style="{StaticResource LeftMenu}" 
        Grid.Column="0"
        / >

    </Grid>
</Window>

同时,需要考虑资源字典

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:view="clr-namespace:ForJon.Ui.Views"
                    xmlns:viewModel="clr-namespace:ForJon.Ui.ViewModels"
                    >

    <Style x:Key="LeftMenu" TargetType="HeaderedContentControl">
        <Setter Property="HeaderTemplate">
            <Setter.Value>
                <DataTemplate>
                        <StackPanel>
                            <Button Content="Add" Command="{Binding AddCommand}" />
                        </StackPanel>
                </DataTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Width" Value="160"/>
    </Style>

</ResourceDictionary>

我只能假设当在ResourceDictionary中绑定时,它找不到ViewModel(虽然我不知道为什么会这样想)。我认为它正在尝试向下多绑定一级... 无论如何,有人能否解释一下为什么它不能从Resource Dictionary中执行。
1个回答

8
这个问题似乎与ResourceDictionary没有什么关系,而是需要将父级DataContext传递到DataTemplate中。
如果您复制Style并将其放入Grid.Resources中,并注释掉资源字典,则可以看到相同的行为。同时打开绑定错误应该会显示。
System.Windows.Data Error: 40 : BindingExpression path error: 'AddCommand' property not found on 'object' ''String'

修复就是通过DataContext获取数据。

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Style x:Key="LeftMenu"
         TargetType="HeaderedContentControl">
    <Setter Property="HeaderTemplate">
      <Setter.Value>
        <DataTemplate>
          <StackPanel DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type HeaderedContentControl}}, Path=DataContext}">
            <Button Command="{Binding AddCommand}"
                    Content="Add" />
          </StackPanel>
        </DataTemplate>
      </Setter.Value>
    </Setter>
    <Setter Property="Width"
            Value="160" />
  </Style>
</ResourceDictionary>

同样的问题也适用于ContentTemplate,但是Template可以正常工作(它使用ControlTemplate)。
<Setter Property="Template">
  <Setter.Value>
    <ControlTemplate TargetType="{x:Type HeaderedContentControl}">
      <StackPanel>
        <Button Command="{Binding AddCommand}"
                Content="Add" />
      </StackPanel>
    </ControlTemplate>
  </Setter.Value>
</Setter>

1
这解决了问题,但肯定有比我所做的更优雅的方法吧?在资源字典中声明DataContext会更好吗?谢谢! - Dave
4
通过相对源绑定获取DataContext并不是什么坏事,当你知道自己在做什么时。然而,如果你询问我的个人意见,我都不会这样做。资源字典的概念是让我们重复使用控件,但是当我们在资源字典中有绑定时,你基本上将Style与一个非常特定的VM和View绑定在一起,这意味着你最好直接在Item本身中定义它。 - Viv
哇,Viv,谢谢你。这轮到我请你喝啤酒了。是的,我能理解你采取这种方法的原因,这真的非常出色,对我帮助很大。 - Dave
@DaveRook 如果我打算在多个视图中使用相同的“Style”来使用此“HeaderedContentControl”,那么我会对“HeaderedContentControl”进行子类化,添加DP并在资源字典中定义样式,并在命令绑定中将其绑定到DP。这样,在我使用此控件的任何视图中,我只需在实际视图的xaml中为DP指定来自VM的命令,我的“Style”就会相应地设置以与之配合工作。 - Viv
@Viv 抱歉...我没有注意到这个问题与WPF有关:在Silverlight for W8/RT中,本地化必须通过绑定来实现....如果您想本地化标准的“空内容”属性,例如,我认为应该通过在资源字典中“样式化”控件来完成......但也许对于WPF来说不是这样的...再次抱歉,回答得很好。 - MAXE
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接