为什么我的自定义装饰器/修饰函数在布尔值更改为true时不起作用?

5

我对装饰器/修饰符知之甚少,但在这里(此处)获得了一个很好的答案,其中使用了它们。

我尝试实现它们,但是它们似乎不像回答者描述的那样起作用。 我已经尽可能地保持一切相同。

这是我的XAML:

<models:TipFocusDecorator x:Name="LoginDecorator" 
         TipText="Enter your username and password and click 'Login'"
         IsOpen="{Binding ShowLoginTip}"
         Grid.Column="1" Grid.Row="1">
    <Image Grid.Column="1" Grid.Row="1" Source="{Binding EnemyImagePath, FallbackValue={StaticResource DefaultImage}}" MaxWidth="500" MaxHeight="500">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="MouseUp">
                <i:InvokeCommandAction Command="{Binding EnemyAttack}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Image>
</models:TipFocusDecorator>

public class TipFocusDecorator : Decorator
{

    public bool IsOpen
    {
        get { return (bool)GetValue(IsOpenProperty); }
        set { SetValue(IsOpenProperty, value); }
    }
    // Using a DependencyProperty as the backing store for Open.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty IsOpenProperty =
        DependencyProperty.Register("IsOpen", typeof(bool), typeof(TipFocusDecorator),
        new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, IsOpenPropertyChanged));


    public string TipText
    {
        get { return (string)GetValue(TipTextProperty); }
        set { SetValue(TipTextProperty, value); }
    }
    // Using a DependencyProperty as the backing store for TipText.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TipTextProperty =
        DependencyProperty.Register("TipText", typeof(string), typeof(TipFocusDecorator), new UIPropertyMetadata(string.Empty));


    public bool HasBeenShown
    {
        get { return (bool)GetValue(HasBeenShownProperty); }
        set { SetValue(HasBeenShownProperty, value); }
    }

    // Using a DependencyProperty as the backing store for HasBeenShown.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty HasBeenShownProperty =
        DependencyProperty.Register("HasBeenShown", typeof(bool), typeof(TipFocusDecorator), new UIPropertyMetadata(false));

    private static void IsOpenPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        var decorator = sender as TipFocusDecorator;

        if ((bool)e.NewValue)
        {
            if (!decorator.HasBeenShown)
                decorator.HasBeenShown = true;

            decorator.Open();
        }

        if (!(bool)e.NewValue)
        {
            decorator.Close();
        }
    }

    TipFocusAdorner adorner;

    protected void Open()
    {
        adorner = new TipFocusAdorner(this.Child);
        var adornerLayer = AdornerLayer.GetAdornerLayer(this.Child);
        adornerLayer.Add(adorner);

        MessageBox.Show(TipText);  // Change for your custom tip Window
        IsOpen = false;
    }

    protected void Close()
    {
        var adornerLayer = AdornerLayer.GetAdornerLayer(this.Child);
        adornerLayer.Remove(adorner);
        adorner = null;
    }

}

以下是 Adorner 类:

public class TipFocusAdorner : Adorner
{
    public TipFocusAdorner(UIElement adornedElement)
        : base(adornedElement)
    {
    }

    protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
    {
        base.OnRender(drawingContext);

        var root = Window.GetWindow(this);
        var adornerLayer = AdornerLayer.GetAdornerLayer(AdornedElement);
        var presentationSource = PresentationSource.FromVisual(adornerLayer);
        Matrix transformToDevice = presentationSource.CompositionTarget.TransformToDevice;

        var sizeInPixels = transformToDevice.Transform((Vector)adornerLayer.RenderSize);
        RenderTargetBitmap rtb = new RenderTargetBitmap((int)(sizeInPixels.X), (int)(sizeInPixels.Y), 96, 96, PixelFormats.Default);

        var oldEffect = root.Effect;
        root.Effect = new BlurEffect();
        rtb.Render(root);
        root.Effect = oldEffect;

        drawingContext.DrawImage(rtb, adornerLayer.TransformToVisual(AdornedElement).TransformBounds(new Rect(adornerLayer.RenderSize)));
        drawingContext.DrawRectangle(new SolidColorBrush(Color.FromArgb(22, 0, 0, 0)), null, adornerLayer.TransformToVisual(AdornedElement).TransformBounds(new Rect(adornerLayer.RenderSize)));
        drawingContext.DrawRectangle(new VisualBrush(AdornedElement) { AlignmentX = AlignmentX.Left, TileMode = TileMode.None, Stretch = Stretch.None },
            null,
            AdornedElement.RenderTransform.TransformBounds(new Rect(AdornedElement.DesiredSize)));
    }
}

最后,这是我的视图模型:

private ICommand testDebug;
public ICommand TestDebug
{
    get
    {
        if (testDebug == null)
        {
            testDebug = new RelayCommand(param => this.TestDebugEx(), null);
        }
        return testDebug;
    }
}
private void TestDebugEx()
{
    ShowLoginTip = true;
    OnPropertyChanged("ShowLoginTip");
}

public bool ShowLoginTip = true;

当我按下调用命令的按钮时,命令运行良好,并且ShowLoginTip的值更改为true。但是,在装饰器中它不执行任何东西。
2个回答

1
在WPF中,绑定需要ShowLoginToolTip成为一个属性。
将其更改为以下内容。
private bool _showLoginToolTip;

public bool ShowLoginToolTip
{
    get
       {
         return _showLoginToolTip;
       }
    set
       {
         _showLoginToolTip = value;
         OnPropertyChanged("ShowLoginTip");
       }
}

private void TestDebugEx()
{
    ShowLoginTip = true;
}

0
我发现这个SO问题和我的类似,这个解决了我的问题: 我的装饰器属性是问题所在。
当创建一个属性,在更改时应该触发重绘,我将这个:
new PropertyMetadata(0.0)
改为了这个:
new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender)(在我的情况下,AffectsRender就足够了,但你的情况可能不同)


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