当 bool 变为 true 时,为什么我的自定义装饰器/装饰器不会起作用?
Why wont my custom decorator / adorner function when bool changes to true?
所以,我对装饰器/装饰器知之甚少,但得到了一个很好的答案,它使用了它们。
我已经尝试实施它们,但它们似乎并不像对给出答案的人那样有效。我尽量让一切保持一致。
这是我的 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;
}
}
这是饰品 class:
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。但是,它不会 运行 装饰器等中的任何东西
要使绑定在 WPF 中工作,ShowLoginToolTip 应该是 属性。
改成这样
private bool _showLoginToolTip;
public bool ShowLoginToolTip
{
get
{
return _showLoginToolTip;
}
set
{
_showLoginToolTip = value;
OnPropertyChanged("ShowLoginTip");
}
}
private void TestDebugEx()
{
ShowLoginTip = true;
}
我发现这个 SO 问题与我的类似,这为我解决了这个问题:
我的装饰器 属性 是问题所在。
在创建更改时应触发重绘的 属性 时,我将其更改为:
new PropertyMetadata(0.0)
对此:
new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender)
(在我的例子中,AffectsRender 就足够了,但是 YMMV)
所以,我对装饰器/装饰器知之甚少,但得到了一个很好的答案
我已经尝试实施它们,但它们似乎并不像对给出答案的人那样有效。我尽量让一切保持一致。
这是我的 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;
}
}
这是饰品 class:
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。但是,它不会 运行 装饰器等中的任何东西
要使绑定在 WPF 中工作,ShowLoginToolTip 应该是 属性。
改成这样
private bool _showLoginToolTip;
public bool ShowLoginToolTip
{
get
{
return _showLoginToolTip;
}
set
{
_showLoginToolTip = value;
OnPropertyChanged("ShowLoginTip");
}
}
private void TestDebugEx()
{
ShowLoginTip = true;
}
我发现这个 SO 问题与我的类似,这为我解决了这个问题:
我的装饰器 属性 是问题所在。
在创建更改时应触发重绘的 属性 时,我将其更改为:
new PropertyMetadata(0.0)
对此:
new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender)
(在我的例子中,AffectsRender 就足够了,但是 YMMV)