绑定到子控件的触发器不起作用

问题描述 投票:-1回答:1

我在WPF窗口上有这个

<local:TestControl>
    <local:TestHost />
</local:MediaPlayer>

这样定义的类

public class TestControl : ContentControl
{
    static TestControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(TestControl), new FrameworkPropertyMetadata(typeof(TestControl)));
        ContentProperty.OverrideMetadata(typeof(TestControl), new FrameworkPropertyMetadata(ContentChanged, CoerceContent));
    }

    private static void ContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var P = d as TestControl;
        P.Host = e.NewValue as TestHost;
    }

    private static object CoerceContent(DependencyObject d, object baseValue) => baseValue as TestHost;

    public static readonly DependencyPropertyKey HostProperty = DependencyProperty.RegisterReadOnly("Host", typeof(TestHost), typeof(TestControl), null);
    public TestHost Host { get => (TestHost)GetValue(HostProperty.DependencyProperty); protected set => SetValue(HostProperty, value); }
}

public class TestHost : Control
{
    static TestHost()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(TestHost), new FrameworkPropertyMetadata(typeof(TestHost)));
    }

    public static readonly DependencyProperty IsPlayingProperty = DependencyProperty.Register("IsPlaying", typeof(bool), typeof(TestHost), 
        new PropertyMetadata(true));
    public bool IsPlaying { get => (bool)GetValue(IsPlayingProperty); set => SetValue(IsPlayingProperty, value); }
}

然后在Generic.xaml中

<Style TargetType="{x:Type local:TestControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:TestControl}">
                <Border>
                    <Grid>
                        <ContentPresenter Content="{TemplateBinding Content}" />
                        <Button x:Name="MyButton" Content="False" />
                    </Grid>
                </Border>
                <ControlTemplate.Triggers>
                    <DataTrigger Value="True" Binding="{Binding Host.IsPlaying, RelativeSource={RelativeSource TemplatedParent}}">
                        <Setter TargetName="MyButton" Property="Content" Value="True" />
                    </DataTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

它应该在按钮中显示“ true”,但仍然是“ false”。

设置主机时设置断点,它会被调用并且主机会正确设置。

我在更改VS选项后显示调试日志中的所有内容,以显示所有绑定的调试信息。

System.Windows.Data Information: 41 : BindingExpression path error: 'Host' property not found for 'object' because data item is null.  This could happen because the data provider has not produced any data yet. BindingExpression:Path=Host.IsPlaying; DataItem=null; target element is 'TestControl' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Information: 20 : BindingExpression cannot retrieve value due to missing information. BindingExpression:Path=Host.IsPlaying; DataItem=null; target element is 'TestControl' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Information: 21 : BindingExpression cannot retrieve value from null data item. This could happen when binding is detached or when binding to a Nullable type that has no value. BindingExpression:Path=Host.IsPlaying; DataItem=null; target element is 'TestControl' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Information: 20 : BindingExpression cannot retrieve value due to missing information. BindingExpression:Path=Host.IsPlaying; DataItem=null; target element is 'TestControl' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Information: 21 : BindingExpression cannot retrieve value from null data item. This could happen when binding is detached or when binding to a Nullable type that has no value. BindingExpression:Path=Host.IsPlaying; DataItem=null; target element is 'TestControl' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=Host.IsPlaying; DataItem=null; target element is 'TestControl' (Name=''); target property is 'NoTarget' (type 'Object')

注意,在触发器之外创建普通绑定确实有效

<Button x:Name="MyButton" Content="{Binding Host.IsPlaying, RelativeSource={RelativeSource TemplatedParent}}" />

如何使此触发器绑定起作用?

c# .net wpf mvvm wpf-controls
1个回答
0
投票

嗯...这是“一种”方式

<Style TargetType="{x:Type local:TestControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:TestControl}">
                <Border>
                    <Grid>
                        <ContentPresenter Content="{TemplateBinding Content}" />
                        <Button x:Name="MyButton" Content="False" Height="50" Width="100" />
                        <TextBox x:Name="IsPlayingHidden" Visibility="Hidden" Text="{Binding Host.IsPlaying, RelativeSource={RelativeSource TemplatedParent}}" />
                    </Grid>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger SourceName="IsPlayingHidden" Property="Text" Value="True">
                        <Setter TargetName="MyButton" Property="Content" Value="True" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

这可行,但是很丑。

它确实看起来像是框架中的错误。

© www.soinside.com 2019 - 2024. All rights reserved.