在WPF界面设计中,Adorner可以为好的界面锦上添花,使用它的方式很多,现在WPF的设计模式一般是MVVM,为了满足需求,可以通过以下两种方式控制Adorner。
1.使用附加属性控制Adorner:
添加一个类,其中包含一个依赖属性,以及一个设置Adorner的方法,依赖属性代码如下:
public static readonly DependencyProperty IsShowAdornerProperty =
DependencyProperty.RegisterAttached("IsShowAdorner", typeof(bool), typeof(AdornerHelper), new PropertyMetadata(true,IsShowChangedCallBack));
private static void IsShowChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var element = d as UIElement;
if (element != null)
{
var adornerLayer = AdornerLayer.GetAdornerLayer(element);
if (adornerLayer!=null)
{
var adorners = adornerLayer.GetAdorners(element);
if (adorners != null && adorners.Count() != 0)
{
var adorner = adorners.FirstOrDefault();
if (adorner == null)
{
return;
}
adorner.Visibility = (bool) e.NewValue ? Visibility.Visible : Visibility.Hidden;
}
}
}
}
这个属性控制Adorner的显示状态。外部设置方法代码:
public static void SetAdorner(DependencyObject obj, Adorner adorner)
{
var element = obj as Visual;
if (element!=null)
{
var adornerLayer = AdornerLayer.GetAdornerLayer(element);
if (adornerLayer==null) throw new NullReferenceException($"在{obj}没发现AdornerLayer");
adornerLayer.Add(adorner);
}
}
在代码中给元素设置Adorner,Adorner的实现方式自选。代码中应用:
<Button x:Name="Button" Width="50" Height="50" Margin="234,67,234.4,203.8" adornerSample:AdornerHelper.IsShowAdorner="True"></Button>
后台代码:
AdornerHelper.SetAdorner(Button,new YouAdorner());
在MVVM模式中可以绑定控制Adorner的显示状况。2.通过Behavior模式控制元素的Adorner
此方式的Adorner采用Xaml的形式定义Adorner的外观,所以需要多设置一个依赖属性AdornerTemplate。
继承实现一个基本的Adorner类,需要修该一些默认的方法,构造函数传入一个元素作为Adorner唯一的子元素。代码:
public class BaseAdorner:Adorner
{
FrameworkElement _frameworkElementAdorner;
public BaseAdorner(UIElement adornedElement,FrameworkElement framework):base(adornedElement)
{
_frameworkElementAdorner = framework;
AddLogicalChild(_frameworkElementAdorner);
AddVisualChild(_frameworkElementAdorner);
}
protected override Visual GetVisualChild(int index)
{
return _frameworkElementAdorner;
}
protected override int VisualChildrenCount
{
get
{
return 1;
}
}
protected override Size ArrangeOverride(Size finalSize)
{
_frameworkElementAdorner.Arrange(new Rect(new Point(0, 0), finalSize));
return finalSize;
}
protected override Size MeasureOverride(Size constraint)
{
_frameworkElementAdorner.Width = constraint.Width;
_frameworkElementAdorner.Height = constraint.Height;
return constraint;
}
}
实现自己的Behavior,代码如下:
public class BaseAdornerBehavior: Behavior<DependencyObject>
{
private BaseAdorner _adorner;
private ContentControl _adornerContentControl;
private readonly Func<bool> _adornerTemplateFactory;
#region 依赖属性
public static readonly DependencyProperty AdornerTemplateProperty = DependencyProperty.Register(
"AdornerTemplate", typeof(DataTemplate), typeof(BaseAdornerBehavior), new PropertyMetadata(new PropertyChangedCallback(
delegate(DependencyObject o, DependencyPropertyChangedEventArgs args)
{
if (null != ((BaseAdornerBehavior)o)._adornerContentControl)
((BaseAdornerBehavior)o)._adornerContentControl.ContentTemplate = (DataTemplate)args.NewValue;
})));
/// <summary>
/// adorner的样式
/// </summary>
public DataTemplate AdornerTemplate
{
get { return (DataTemplate) GetValue(AdornerTemplateProperty); }
set { SetValue(AdornerTemplateProperty, value); }
}
public static readonly DependencyProperty AdornerVisibleProperty = DependencyProperty.Register(
"AdornerVisible", typeof(Visibility), typeof(BaseAdornerBehavior), new PropertyMetadata((object)Visibility.Hidden,new PropertyChangedCallback((
(o, args) =>
{
if (null != ((BaseAdornerBehavior)o)._adornerContentControl)
((BaseAdornerBehavior)o)._adornerContentControl.Visibility = (Visibility)args.NewValue;
}))));
/// <summary>
/// adorner可见性
/// </summary>
public Visibility AdornerVisible
{
get { return (Visibility) GetValue(AdornerVisibleProperty); }
set { SetValue(AdornerVisibleProperty, value); }
}
#endregion
#region 命令
public ICommand ShowAdornerCommand { get; private set; }
public ICommand HideAdornerCommand { get; private set; }
#endregion
public BaseAdornerBehavior()
{
_adornerTemplateFactory = () =>
{
if (AdornerTemplate != null)
{
//获取元素的adornerlayer
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(AssociatedObject as UIElement);
if (null == adornerLayer)
throw new NullReferenceException(string.Format("No adorner found in attached object: {0}",
AssociatedObject));
//
_adornerContentControl = new ContentControl();
//添加adorner
adornerLayer.Add(_adorner = new BaseAdorner(AssociatedObject as UIElement, _adornerContentControl));
//加载样式
_adornerContentControl.Content = AdornerTemplate.LoadContent();
_adornerContentControl.Visibility = Visibility.Visible;
//绑定margin属性到adorner
Binding bindingMargin = new Binding("AdornerMargin");
bindingMargin.Source = this;
BindingOperations.SetBinding(_adorner, ContentControl.MarginProperty, bindingMargin);
}
return true;
};
//初始化命令
ShowAdornerCommand=new ActionCommand(() =>
{
var dtContext = (this.AssociatedObject as FrameworkElement).DataContext;
if (null == _adornerContentControl.DataContext)
_adornerContentControl.DataContext = dtContext;
_adornerContentControl.Visibility = Visibility.Visible;
});
HideAdornerCommand=new ActionCommand((() =>
{
_adornerContentControl.Visibility=Visibility.Hidden;
//if (_adornerContentControl.IsMouseOver)
//{
// _adornerContentControl.MouseLeave -= (s, e) =>
// {
// _adornerContentControl.Visibility = AdornerVisible;
// };
// _adornerContentControl.MouseLeave += (s, e) =>
// {
// _adornerContentControl.Visibility = AdornerVisible;
// };
//}
}));
}
#region override
protected override void OnAttached()
{
base.OnAttached();
_adornerTemplateFactory();
}
#endregion
}
代码没什么好说的,自己理解。
代码中的应用,哦,忘了说这个需要Blend的sdk,在Nuget中获取,搜索Blend就能找到,代码:
<Custom:Interaction.Behaviors>
<adornerBehavior:BaseAdornerBehavior AdornerTemplate="{StaticResource AdornerDataTemplate}">
<Custom:Interaction.Triggers>
<Custom:EventTrigger SourceName="arc" EventName="MouseEnter">
<Custom:InvokeCommandAction CommandName="ShowAdornerCommand"/>
</Custom:EventTrigger>
<Custom:EventTrigger SourceName="arc" EventName="MouseLeave">
<Custom:InvokeCommandAction CommandName="HideAdornerCommand"/>
</Custom:EventTrigger>
</Custom:Interaction.Triggers>
</adornerBehavior:BaseAdornerBehavior>
</Custom:Interaction.Behaviors>
需要添加Adorner的元素添加以上代码,上面的Adorner的模板是我自己定义的。代码就不贴了。
总结一下:两种方式难度都不大,但是第二种方式更现代一点。当Adorner仅仅做到提示,没有复杂的处理时,当Adorner有业务或者更高级的功能要做时,两者就有区别了。