WPF - DependencyProperty的IsEnabled绑定无法正常工作

4

我在窗口中定义了一个依赖属性,如下所示:

public static readonly DependencyProperty IsGenericUserProperty = DependencyProperty.Register("IsGenericUser", typeof (bool), typeof (MainWindow));
public bool IsGenericUser
{
    get { return (bool) GetValue(IsGenericUserProperty); }
    set { SetValue(IsGenericUserProperty, value); }
}

在我的窗口构造函数中,我设置了包含按钮的容器的数据上下文:
QuickListButtonsStackPanel.DataContext = this;

我将依赖属性绑定到按钮的IsEnabled属性上: ```html

我将依赖属性绑定到按钮的IsEnabled属性上:

```
<Button IsEnabled="{Binding IsGenericUser}" .../>

在启动时,IsGenericUser为true,因此按钮是启用的。当我将IsGenericUser设置为false时,按钮被禁用。但是,如果我再次将IsGenericUser设置为true,则按钮不会发生任何变化,仍然处于禁用状态。

我做错了什么?

谢谢!

编辑: 这是我使用的按钮样式。这个样式导致了问题(如果按钮没有自定义样式,它就可以正常工作):

<Style x:Key="BlackButtonStyle" TargetType="{x:Type Button}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <ControlTemplate.Resources>
                    <Storyboard x:Key="MouseOverActivating">
                        <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
                            <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF2F2F2F"/>
                            <SplineColorKeyFrame KeyTime="00:00:00.1270000" Value="#FF2391FF"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>
                    <Storyboard x:Key="MouseOverDeactivating">
                        <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="rectangle">
                            <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF2391FF"/>
                            <SplineColorKeyFrame KeyTime="00:00:00.2200000" Value="#FF2F2F2F"/>

                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>
                    <Storyboard x:Key="PressActivating">
                        <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
                            <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF2391FF"/>
                            <SplineColorKeyFrame KeyTime="00:00:00.1370000" Value="#FF48D6FF"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>
                    <Storyboard x:Key="PressedDeactivating" FillBehavior="Stop" >
                        <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="rectangle">
                            <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF48D6FF"/>
                            <SplineColorKeyFrame KeyTime="00:00:00.2370000" Value="#FF2391FF"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>
                    <Storyboard x:Key="DisableActivating">
                        <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
                            <SplineColorKeyFrame KeyTime="00:00:00" Value="#FFA7A7A7"/>
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>
                </ControlTemplate.Resources>
                <Grid>
                    <Rectangle Stroke="Transparent" RadiusX="5" RadiusY="5" x:Name="rectangle">
                        <Rectangle.Fill>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="#FF000000" Offset="0"/>
                                <GradientStop Color="#FF2F2F2F" Offset="1"/>
                            </LinearGradientBrush>
                        </Rectangle.Fill>
                    </Rectangle>
                    <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" RecognizesAccessKey="True" OpacityMask="{x:Null}"/>
                    <Rectangle Stroke="Transparent" RadiusX="5" RadiusY="5" x:Name="WhiteGlow">
                        <Rectangle.Fill>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="#5BFFFFFF" Offset="0"/>
                                <GradientStop Color="#00FFFFFF" Offset="0.5"/>
                            </LinearGradientBrush>
                        </Rectangle.Fill>
                    </Rectangle>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsCancel" Value="False"/>
                    <EventTrigger RoutedEvent="FrameworkElement.Loaded"/>
                    <Trigger Property="IsFocused" Value="True">
                        <Trigger.ExitActions>
                            <BeginStoryboard Storyboard="{StaticResource MouseOverActivating}" x:Name="MouseOverActivating_BeginStoryboard2"/>
                        </Trigger.ExitActions>
                        <Trigger.EnterActions>
                            <BeginStoryboard Storyboard="{StaticResource MouseOverActivating}" x:Name="MouseOverActivating_BeginStoryboard1"/>
                        </Trigger.EnterActions>
                    </Trigger>
                    <Trigger Property="IsDefaulted" Value="True"/>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Trigger.ExitActions>
                            <BeginStoryboard Storyboard="{StaticResource MouseOverDeactivating}" x:Name="MouseOverDeactivating_BeginStoryboard"/>
                        </Trigger.ExitActions>
                        <Trigger.EnterActions>
                            <BeginStoryboard Storyboard="{StaticResource MouseOverActivating}" x:Name="MouseOverActivating_BeginStoryboard"/>
                        </Trigger.EnterActions>
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                        <Trigger.EnterActions>
                            <BeginStoryboard x:Name="PressActivating_BeginStoryboard" Storyboard="{StaticResource PressActivating}"/>
                        </Trigger.EnterActions>
                        <Trigger.ExitActions>
                            <BeginStoryboard x:Name="PressedDeactivating_BeginStoryboard" Storyboard="{StaticResource PressedDeactivating}"/>
                        </Trigger.ExitActions>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="False">
                        <Trigger.EnterActions>
                            <BeginStoryboard Storyboard="{StaticResource DisableActivating}" x:Name="DisableActivating_BeginStoryboard"/>
                        </Trigger.EnterActions>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

抱歉,在使用我上面描述的一切内容进行测试项目时,所有工作都正常。可能是我的项目中还有其他特定问题。 - Gus Cavalcanti
1
还有其他东西会针对那个按钮吗?你是否通过代码设置了任何属性或应用了任何动画? - rmoore
是的,我确实将动画应用到按钮的样式上了。这可能是导致问题的原因。如果我不使用按钮样式,一切都正常工作。 - Gus Cavalcanti
你的按钮有命令吗?如果命令的CanExecute返回false(或者你没有通知CanExecute已经改变),那么按钮将被禁用。 - Eddie Deyo
不,没有命令。谢谢。 - Gus Cavalcanti
那种样式对我使用按钮也有效。但是,如果您将单击处理程序分配给按钮,则“已启用”和“已禁用”之间没有视觉差异,您可以在其中设置断点并查看其工作情况。 - rmoore
4个回答

6
你是如何将属性设置为False/True的?如果我按照你的代码复制,它可以完美地工作。可能有其他因素影响了它,比如按钮上的动画或清除绑定的东西。你能否提供更多的代码来帮助澄清可能导致这种情况的原因?
以下是我测试过的代码:
<Window x:Class="WpfApplication6.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1"
    Height="300"
    Width="300">
<Grid>
    <StackPanel x:Name="QuickListButtonsStackPanel">
        <Button IsEnabled="{Binding IsGenericUser}"
                Content="Bound Button" />
        <Button Content="Change Binding"
                Click="Button_Click" />
    </StackPanel>
</Grid>

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        QuickListButtonsStackPanel.DataContext = this;
    }
    public static readonly DependencyProperty IsGenericUserProperty =
        DependencyProperty.Register(
            "IsGenericUser",
            typeof(bool),
            typeof(Window1));

    public bool IsGenericUser
    {
        get { return (bool)GetValue(IsGenericUserProperty); }
        set { SetValue(IsGenericUserProperty, value); }
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        IsGenericUser = !IsGenericUser;
    }
}

编辑: 您还可以添加一个文本框来查看它是否正常工作,

<Button x:Name="uiButton"
        IsEnabled="{Binding IsGenericUser}"
        Style="{StaticResource BlackButtonStyle}"
        Content="Bound Button"/>
<TextBlock Text="{Binding ElementName=uiButton, Path=IsEnabled}" />

看起来问题只存在于样式的storyboard中,如果你添加了那个,它是否仍然显示IsEnabled为false,而不应该是这样的?


谢谢rmoore。你是对的 - 我在按钮上使用的样式导致了这种奇怪的行为。我已经在问题中包含了样式。我在样式中漏掉了什么?非常感谢! - Gus Cavalcanti
这是我所做的: 1)创建了一个名为DisableDeactivating的新故事板,并设置FillBehavior="Stop"。 2)然后,在IsEnabled = false触发器的Trigger.ExitActions中添加了一个DisableDeactivating的BeginStoryboard。 - Gus Cavalcanti

0
尝试
<Button IsEnabled={Binding Path=IsGenericUser}" ... />

Path= 不是必需的,但它可能会产生影响。

而且在数据上下文中使用 this,你确定这样做是正确的吗?这不会使控件本身成为上下文。我还没有看到你的其余代码,但那似乎不对。


"this" 是当前类。因此,将 "this" 分配给 DataContext 将分配当前类给它(在我的情况下是我的窗口)。窗口具有 DP,所以是的,这是正确的。 - Gus Cavalcanti

0
如果有人遇到同样的问题 - 很可能是您的DataContext未设置或动态更改为另一个对象。这在一些包含许多不同控件的模板中会发生。

0

1) 创建了一个名为DisableDeactivating的新故事板,并设置FillBehavior="Stop"(尼古拉斯的建议) 2) 然后,在IsEnabled = false触发器的Trigger.ExitActions中添加了一个DisableDeactivating的BeginStoryboard。


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