WPF入门教程连串十三——倚重属性(三)葡京娱乐注册

心想事成服务层与api层共用,也固然标明Service层就是api层。

季、 只读倚重属性

  • 着重类及接口

    • System.Web.Http.Dispatcher.DefaultHttpControllerSelector

    webpai采取控制器的默认实现,可以又写SelectController方法

    • System.Web.Http.Controllers.ApiControllerActionSelector

    webapi拔取指定控制器下之action的默认实现,能够再一次写SelectAction方法。

    • System.Web.Http.ApiController

    api控制器的基类,继承给斯之好像都可成为Api控制器

     

  • 类与接口关系图 api自定义扩充实现

  于原先当对非WPF的力量来说,对于类似的性质的包中,平日会对那一个欲表露于外界就读操作的字段封装成只念属性,同样以WPF中吗提供了特念属性之概念,如一些
WPF控件的指属性是一味念之,它们常用来报告控件的状态及信,像IsMouseOver等属性,
那么在这多少个上针对其赋值就从未有过意义了。
或许你也相会时有发生诸如此类的疑问:为何非选用相似的.Net属性提供出来吧?一般的特性为得绑定到元素上呀?这一个是由有些地点要要用到就念依赖属性,比如
Trigger等,同时为因为里或爆发差不多少个提供者修改其价值,所以用.Net属性就不可能做到上之深任了。

葡京娱乐注册 1

  那么一个但是读依赖属性怎么开创为?其实创立一个独自读的依属性与创办一个貌似的因属性茂名小异。不同的地点就是是DependencyProperty.Register变成了DependencyProperty.RegisterReadOnly。和前面的一般性因属性一样,它用再次来到一个
DependencyPropertyKey。而且只供一个GetValue给外部,这样即便足以像相似属性一样以了,只是不克当外部设置它的值罢了。

api注册流程

下我们便就此一个大概的例子来概括一下:

葡京娱乐注册 2

public partial class WindowReadOnly : Window
 {
     public WindowReadOnly ()
     {
         InitializeComponent();

         //用SetValue的方法来设置值
         DispatcherTimer timer =
             new DispatcherTimer(TimeSpan.FromSeconds(1),
                                 DispatcherPriority.Normal,
                                 (object sender, EventArgs e)=>
                                 {
                                     int newValue = Counter == int.MaxValue ? 0 : Counter + 1;
                                     SetValue(counterKey, newValue);
                                 },
                                 Dispatcher);

     }

     //属性包装器,只提供GetValue
     public int Counter
     {
         get { return (int)GetValue(counterKey.DependencyProperty); }
     }

     //用RegisterReadOnly来代替Register来注册一个只读的依赖属性
     private static readonly DependencyPropertyKey counterKey =
         DependencyProperty.RegisterReadOnly("Counter",
                                             typeof(int),
                                             typeof(WindowReadOnly),
                                             new PropertyMetadata(0));
 }

假使实现Servie层的Controller。

 

  • 所有服务类都待后续给ApiController类,让服务类拥有控制器的特征
    ApiServier类代码(继承ApiController此可,设置服务基类用于深扩充):

    public class ApiService:System.Web.Http.ApiController
    {
    }

 

TestServer类代码:

  
XAML代码:

public class TestService:ApiService
{
    public string Get()
    {
        return "Get-Test";
    }
}
<Window x:Name="winReadOnly" x:Class="WpfApp1.WindowReadOnly"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="WindowDepend" Height="300" Width="300">
    <Grid>
        <Viewbox>
            <TextBlock Text="{Binding ElementName=winReadOnly, Path=Counter}" />
        </Viewbox>
    </Grid>
</Window>

落实服务类,且独具ApiController的力量

 

  • 实现瑟维斯(Service)(Service)Container类,实现服务类的缓存,并用以Controller的选项看似,获取服务类代码如下:

    private void Init()
    {

    var assembly = System.Reflection.Assembly.GetExecutingAssembly();
    var ls = assembly.GetTypes().Where(x => typeof(Services.ApiService).IsAssignableFrom(x));
    foreach(var item in ls)
    {
        _apis.Add(item.FullName, item);
    }
    

    }

  • 重写api选择controller类代码:

    public class CustomSelectController:System.Web.Http.Dispatcher.DefaultHttpControllerSelector
    {

    public CustomSelectController(System.Web.Http.HttpConfiguration config) : base(config)
    {
    
    }
    
    public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
    {
        var routeData = request.GetRouteData().Values;
        foreach( var route in routeData)
        {
            if(route.Key == "controller")
            {
                //找controller
                var controllerType = ServicesContainer.CreateInstance().Apis
                    .Where(x => x.Key.ToLower().IndexOf(route.Value.ToString() + "service") > 0).FirstOrDefault();
                if (controllerType.Value!=null)
                {
                    return new DyControllerDescriptor(request.GetConfiguration(), controllerType.Value);
                }
            }
        }
    
        return base.SelectController(request);
    }
    

    }

 

注意:

功效使下图所示: 

  1. 择Controller类必须有一个参数的构造函数,构造函数传入为httpConfiguration类
  2. 重写SelectController方法,实现从ServiceContainer中获取ApiService实现类
  3. 重写ActionSelector类

    public class CustomActionActivator:System.Web.Http.Controllers.ApiControllerActionSelector
    {

    public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
    {
        if (!(controllerContext.ControllerDescriptor is DyControllerDescriptor))
        {
            return base.SelectAction(controllerContext);
        }
    
        var realType = controllerContext.ControllerDescriptor as DyControllerDescriptor;
    

 葡京娱乐注册 3

        Type[] types = new Type[0];
        System.Reflection.MethodInfo methodInfo = realType.ControllerInfo.GetMethod("Get", 
            types);

        return new DyActionDescriptor(controllerContext.Configuration, controllerContext.ControllerDescriptor, methodInfo);
    }
}

五、 附加属性

  • 注意:

    1. 此类不另行写吧可兑现ApiService(Service)类的履行,此类重要是处理在Action执行前一个些额外操作。
    2. 从中我们吧堪看来Action的履也是用MethodInfo这多少个近乎的实例。

     

  • Global.cs中流入Api路由时,必须在Mvc注入路由以前

    protected void Application_Start()
    {

    common.ServicesContainer.CreateInstance();
    
    AreaRegistration.RegisterAllAreas();
    
    //必须放在RouteConfig.RegisterRoutes前面
    GlobalConfiguration.Configure((config) =>
    {
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    });
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
    
    GlobalConfiguration.Configuration.Services.Replace(typeof(System.Web.Http.Dispatcher.IHttpControllerSelector),
        new common.CustomSelectController(GlobalConfiguration.Configuration));
    GlobalConfiguration.Configuration.Services.Replace(typeof(System.Web.Http.Controllers.IHttpActionSelector), new common.CustomActionActivator());
    

    }

     
现在大家更持续探索其余一栽特殊的看重属性——附加属性。附加属性是千篇一律种新鲜的借助属性。那是WPF的性状有,通俗的明亮起来就是,别人有属性,由于您同他出了关系之所以若吧来了是属于他的属性。

运作结果:

     
附加属性是说一个属性本来不属有对象,但鉴于某种要求使受新兴附加上,也就是是拿目的放入一个一定环境后对象才具备的性就叫附加属性,附加属性的效能就是拿性与数据类型解耦,让数据类型的计划性更加灵活,举例,一个TextBox被放在不同之布局容器被时常便会合起差之布局属性,那个性就是由于布局容
器为TextBox附加上之,附加属性之原形就是借助属性,二者只是在登记和包装器上有好几别。  

葡京娱乐注册 4

     
附加属性是指属性的一致种特别模式,它可被用户以一个因素被安装任何因素的习性。一般的话,附加属性是用以一个父元素定位其他因素布局
的。就比如Grid和DockPanel元素就含有附加属性。Grid使用附加属性来指定包含子元素的一定行和列,而DockPanel使用附加属性是来指
定子元素应该靠在面板中之何地地方。

     
附加属性就是温馨一向不那么些特性,在少数上下文中需要就叫增大上。比如StackPanel的Grid.Row属性,即便我们定义StackPanel类时定义一个Row属性是不曾意思之,因为大家并不知道一定会放在Grid里,这样固然导致了浪费。

譬如,上边转场控件的概念使用了Grid的Row属性来以自我定位到一定的行中。

   <Grid>

        <Grid.RowDefinitions>

            <RowDefinition Height="101*"/>

            <RowDefinition Height="80"/>

            <RowDefinition Height="80"/>

        </Grid.RowDefinitions>

        <StackPanel Grid.Row="0" >

 

 

    
即使对一个见怪不怪的WPF开发人士来说,明白指以及叠加属性并不一定是须的,可是明白好WPF系统的整套运行机制对于升级WPF应用技术是颇首要的。

    
使用附加属性,可以避开可能相会制止一个关乎遇的两样对象在运行时相互传送音信的编码约定。一定好本着周边的基类设置属性,以便每个对象仅需要得到和
设置该属性即可。可是,你可能想以多状况下这样做,这会要您的基类最后充斥在大量可是共享的属性。它仍然可能会面引入以下情状:在数百单后代中,只发些许只
后代尝试利用一个性质。这样的切近设计相当糟糕。为了化解这问题,我们接纳附加属性概念来允许对象啊未是由于她和谐的类协会定义的性能赋值。在创造对象树被之各样相关对象后,在运转时从子对象读博此值。

  最好之例子就是布局面板。每一个布局面板还要好故意的方法来协会她的子元素。如Canvas需要Top和left来布
局,DockPanel需要Dock来布局。当然你吗可以描绘自己之布局面板(在达标等同首著作被我们本着布局进行了于密切的追究,假诺爆发无明了的仇敌也可重回顾一下)。

    下面代码中之Button
就是之所以了Canvas的Canvas.Top和Canvas.Left=”20″
来展开布局定位,那么这点儿单就是是传说被的叠加属性。

<Canvas>
    <Button Canvas.Top="20" Canvas.Left="20" Content="Knights Warrior!"/>
</Canvas>

 

  定义附加属性之法门与概念依赖属性的章程同样,后面大家是运DependencyProperty.Register来注册一个负属性,只是在报属性时接纳的是RegisterAttach()方法。那多少个RegisterAttached的参数和
Register是完全一致的,那么Attached(附加)那一个概念而从何而来呢?

  其实咱们下依赖属性,从来于Attached(附加)。大家报了名(构造)一个因属性,然后在DependencyObject中经过
GetValue和SetValue来操作是仗属性,也即便是把此仗属性通过如此的章程关联到了此DependencyObject上,只可是是
通过封装CLR属性来齐的。那么RegisterAttached又是咋样的也?

下边我们来拘禁一个极致简便的以:首先大家报了名(构造)一个增大属性

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Media;



namespace WpfApp1.Services

{

    public class TurnoverManager : DependencyObject

    {

        //通过静态方法的形式暴露读的操作

        public static double GetAngle(DependencyObject obj)

        {

            return (double)obj.GetValue(AngleProperty);

        }



        //通过静态方法的形式暴露写的操作

        public static void SetAngle(DependencyObject obj, double value)

        {

            obj.SetValue(AngleProperty, value);

        }

        //通过使用RegisterAttached来注册一个附加属性

        public static readonly DependencyProperty AngleProperty =

            DependencyProperty.RegisterAttached("Angle", typeof(double), typeof(TurnoverManager), new PropertyMetadata(0.0, OnAngleChanged));



        //根据附加属性中的值,当值改变的时候,旋转相应的角度。

        private static void OnAngleChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)

        {

            var element = obj as UIElement;

            if (element != null)

            {

                element.RenderTransformOrigin = new Point(0.5, 0.5);

                element.RenderTransform = new RotateTransform((double)e.NewValue);

            }

        }     

    }

}

 

下一场,大家于程序中运用此我们和好定义的叠加属性

<Window x:Class="WpfApp1.WindowTurnover"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:local="clr-namespace:WpfApp1.Services"

        Title="WindowTurnover" Height="400" Width="500" Loaded="Window_Loaded">

    <Grid>

        <Grid.RowDefinitions>

            <RowDefinition Height="313*"/>

            <RowDefinition Height="57*"/>

        </Grid.RowDefinitions>

        <Canvas Grid.Row="0">

            <Ellipse Name="ellipseRed" Fill="Red" Width="100" Height="60" Canvas.Left="56"

                     Canvas.Top="98" local:TurnoverManager.Angle="{Binding ElementName=sliderAngle, Path=Value}"/>

            <Rectangle Name="ellipseBlue" Fill="Blue" Width="80" Height="80" Canvas.Left="285"

                       Canvas.Top="171" local:TurnoverManager.Angle="45" />

            <Button  Name="btnWelcome" Content="欢迎光临" Canvas.Left="265" Canvas.Top="48" FontSize="20" local:TurnoverManager.Angle="60"/>

        </Canvas>

        <WrapPanel Grid.Row="1">

            <Label Content="角度大小" />

            <Slider x:Name="sliderAngle" Minimum="0" Maximum="240" Width="300" />
        </WrapPanel>

    </Grid>

</Window>

于XAML中就得应用刚才注册(构造)的增大属性了:如下图。

葡京娱乐注册 5

经过调整角度值,显示不同之效能如下两贪图。图1,图2。

 葡京娱乐注册 6

                               图1

 葡京娱乐注册 7

                          图2