In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Network Security >
Share
Shulou(Shulou.com)06/01 Report--
1. Preface
This article introduces how to inherit and customize Shape, but I'm afraid that, in fact, 99 of the 100 xaml programmers won't use it. I wrote it because I learned it anyway and took it as a note.
Through this article, you can learn the following knowledge points:
Customize the Shape.
DeferRefresh mode.
Application of InvalidateArrange.
two。 Derived from Path
Most of the Shape in UWP are sealed classes-- except for Path. So custom Shape can only be derived from Path. Template10 gives this example: RingSegment.
As you can see from this class, the custom Shape is simply done by calling private void UpdatePath () to assign a value to the Path.Data when the property value of each custom property changes or SizeChanged.
RingSegment.StartAngle = 30th RingSegment.EndAngle = 330nRingSegment.Radius = 50X RingSegment.InnerRadius = 30th. BeginUpdate, EndUpdate and DeferRefresh
This code creates a problem: every time you change the value of an attribute, UpdatePath () is called, so isn't it repeated four times?
As a matter of fact, it will, and obviously the author of this class has also considered this problem, so the public void BeginUpdate () and public void EndUpdate () functions are provided.
/ Suspends path updates until EndUpdate is called;/// public void BeginUpdate () {_ isUpdating = true;} / Resumes immediate path updates every time a component property value changes. Updates the path./// public void EndUpdate () {_ isUpdating = false; UpdatePath ();}
Use these two methods to rewrite the above code, and that's it:
Try {RingSegment.BeginUpdate (); RingSegment.StartAngle = 30; RingSegment.EndAngle = 330; RingSegment.Radius = 100; RingSegment.InnerRadius = 80;} finally {RingSegment.EndUpdate ();}
This ensures that UpdatePath () is executed only once when EndUpdate () is called.
In WPF, DeferRefresh is a more mature solution. It is believed that many developers have used DataGrid more or less (mainly through CollectionView or CollectionViewSource). You can refer to DataSourceProvider for a typical implementation. This approach is also implemented through AdvancedCollectionView in UWPCommunityToolkit.
Add the following implementation to RingSegment:
Private int _ deferLevel;public virtual IDisposable DeferRefresh () {+ + _ deferLevel; return new DeferHelper (this);} private void EndDefer () {Debug.Assert (_ deferLevel > 0);-- _ deferLevel; if (_ deferLevel = = 0) {UpdatePath ();}} private class DeferHelper: IDisposable {public DeferHelper (RingSegment source) {_ source = source;} private RingSegment _ source Public void Dispose () {GC.SuppressFinalize (this); if (_ source! = null) {_ source.EndDefer (); _ source = null;}
The use is as follows:
Using (RingSegment.DeferRefresh ()) {RingSegment.StartAngle = 30; RingSegment.EndAngle = 330; RingSegment.Radius = 100; RingSegment.InnerRadius = 80;}
There are two benefits to using DeferRefresh mode:
The calling code is relatively simple.
Use _ deferLevel to determine whether UpdatePath () is needed, so that UpdatePath () will only be executed once even if DeferRefresh () is called multiple times. For example, the following call method:
Using (RingSegment.DeferRefresh ()) {RingSegment.StartAngle = 30; RingSegment.EndAngle = 330; RingSegment.Radius = 50; RingSegment.InnerRadius = 30; using (RingSegment.DeferRefresh ()) {RingSegment.Radius = 51; RingSegment.InnerRadius = 31;}}
You may think that the average person will not write so complicated, but the DeferRefresh pattern makes sense in complex scenarios. Suppose you are updating a complex UI, which is driven by many code modules, but it is not clear whether DeferRefresh () has been called elsewhere on the UI that needs to be updated, and the cost of creating a DeferHelper is much lower than that of updating a complex UI, so executing DeferRefresh () once is a reasonable choice.
Thread safety issues are taken into account when you see the code conditioned reflection of + + _ deferLevel, but you worry too much. UWP requires that code that operates on UI can only be executed in UI threads, so in theory all UIElement and all its operations are thread-safe.
4. InvalidateArrange
Calling DeferRefresh every time you change a property is obviously not a smart thing to do, and it's not possible in XAML. Another mechanism to delay execution is to use the public IAsyncAction RunAsync (CoreDispatcherPriority priority, DispatchedHandler agileCallback) function of CoreDispatcher to execute work items asynchronously. It may take a whole article to explain RunAsync in detail. Simply put, the role of RunAsync is to send work items to a queue from which UI threads get work items and execute them when they are available. InvalidateArrange is a typical example of taking advantage of this mechanism. The explanation of InvalidateArrange on MSDN is:
Invalidates the arrangement state (layout) of the UIElement. After expiration, UIElement updates its layout asynchronously.
The logic of InvalidateArrange is simplified as follows:
Protected bool ArrangeDirty {get; set;} public void InvalidateArrange () {if (ArrangeDirty = = true) return; ArrangeDirty = true; Dispatcher.RunAsync (Windows.UI.Core.CoreDispatcherPriority.Normal, () = > {ArrangeDirty = false; lock (this) {/ / Measure / / Arrange}});}
After calling InvalidateArrange, mark ArrangeDirty as True, and then asynchronously execute Measure and Arrange code for layout. Multiple calls to InvalidateArrange check the status of the ArrangeDirty to avoid repeated execution. With InvalidateArrange, we can call InvalidateArrange in the custom property value change event of RingSegment, which triggers the LayoutUpdated asynchronously and changes the Path.Data in it.
The modified code is as follows:
Private bool _ realizeGeometryScheduled;private Size _ orginalSize;private Direction _ orginalDirection;private void OnStartAngleChanged (double oldStartAngle, double newStartAngle) {InvalidateGeometry ();} private void OnEndAngleChanged (double oldEndAngle, double newEndAngle) {InvalidateGeometry ();} private void OnRadiusChanged (double oldRadius, double newRadius) {this.Width = this.Height = 2 * Radius; InvalidateGeometry ();} private void OnInnerRadiusChanged (double oldInnerRadius, double newInnerRadius) {if (newInnerRadius < 0) {throw new ArgumentException ("InnerRadius can't be a negative value.", "InnerRadius") } InvalidateGeometry ();} private void OnCenterChanged (Point? OldCenter, Point? NewCenter) {InvalidateGeometry ();} protected override Size ArrangeOverride (Size finalSize) {if (_ realizeGeometryScheduled = = false & & _ orginalSize! = finalSize) {_ realizeGeometryScheduled = true; LayoutUpdated + = OnTriangleLayoutUpdated; _ orginalSize = finalSize;} base.ArrangeOverride (finalSize); return finalSize;} protected override Size MeasureOverride (Size availableSize) {return new Size (base.StrokeThickness, base.StrokeThickness);} public void InvalidateGeometry () {InvalidateArrange () If (_ realizeGeometryScheduled = = false) {_ realizeGeometryScheduled = true; LayoutUpdated + = OnTriangleLayoutUpdated;}} private void OnTriangleLayoutUpdated (object sender, object e) {_ realizeGeometryScheduled = false; LayoutUpdated-= OnTriangleLayoutUpdated; RealizeGeometry ();} private void RealizeGeometry () {/ / other code here Data = pathGeometry;}
This code refers to the Silverlight version of ExpressionSDK. ExpressionSDK provides some Shape for reference. (after installing Blend, you can usually find it in this location: C:\ Program Files (x86)\ Microsoft SDKs\ Expression\ Blend\ Silverlight\ v5.0\ Libraries\ Microsoft.Expression.Drawing.dll.) because it is closer to UWP than WPF,Silverlight, many of the code and experience of Silverlight are more valuable. If you encounter difficulties, you might as well find some Silverlight code for reference.
InvalidateArrange belongs to the core API, and the document is also full of words such as "usually not recommended", "usually unnecessary", "use it carefully" and so on, so it is best to be careful when using it. If it is not a performance-sensitive situation, it is recommended to use the Template10 approach.
5. Using TemplatedControl to implement
In addition to deriving from Path, the functionality of custom Shape can also be implemented in TemplatedControl, which should generally be the simplest and most general way. The following code implements a triangle using TemplatedControl:
[TemplatePart (Name = PathElementName,Type = typeof (Path))] [StyleTypedProperty (Property = nameof (PathElementStyle), StyleTargetType = typeof (Path))] public class TriangleControl: Control {private const string PathElementName = "PathElement"; public TriangleControl () {this.DefaultStyleKey = typeof (TriangleControl); this.SizeChanged + = OnTriangleControlSizeChanged;} / identifies the Direction dependency attribute. / public static readonly DependencyProperty DirectionProperty = DependencyProperty.Register ("Direction", typeof (Direction), typeof (TriangleControl), new PropertyMetadata (Direction.Up, OnDirectionChanged)); / get or set the value of Direction / public Direction Direction {get {return (Direction) GetValue (DirectionProperty);} set {SetValue (DirectionProperty, value) }} private static void OnDirectionChanged (DependencyObject obj, DependencyPropertyChangedEventArgs args) {var target = obj as TriangleControl; var oldValue = (Direction) args.OldValue; var newValue = (Direction) args.NewValue; if (oldValue! = newValue) target.OnDirectionChanged (oldValue, newValue) } protected virtual void OnDirectionChanged (Direction oldValue, Direction newValue) {UpdateShape ();} / get or set the value of PathElementStyle / public Style PathElementStyle {get {return (Style) GetValue (PathElementStyleProperty);} set {SetValue (PathElementStyleProperty, value) }} / identifies the PathElementStyle dependency attribute. / / public static readonly DependencyProperty PathElementStyleProperty = DependencyProperty.Register ("PathElementStyle", typeof (Style), typeof (TriangleControl), new PropertyMetadata (null)); private Path _ pathElement; public override void OnApplyTemplate () {base.OnApplyTemplate (); _ pathElement = GetTemplateChild ("PathElement") as Path;} private void OnTriangleControlSizeChanged (object sender, SizeChangedEventArgs e) {UpdateShape () } private void UpdateShape () {var geometry = new PathGeometry (); var figure = new PathFigure {IsClosed = true}; geometry.Figures.Add (figure); switch (Direction) {case Direction.Left: figure.StartPoint = new Point (ActualWidth, 0) Var segment = new LineSegment {Point = new Point (ActualWidth, ActualHeight)}; figure.Segments.Add (segment); segment = new LineSegment {Point = new Point (0, ActualHeight / 2)}; figure.Segments.Add (segment); break Case Direction.Up: figure.StartPoint = new Point (0, ActualHeight); segment = new LineSegment {Point = new Point (ActualWidth / 2,0)}; figure.Segments.Add (segment); segment = new LineSegment {Point = new Point (ActualWidth, ActualHeight)}; figure.Segments.Add (segment) Break; case Direction.Right: figure.StartPoint = new Point (0,0); segment = new LineSegment {Point = new Point (ActualWidth, ActualHeight / 2)}; figure.Segments.Add (segment); segment = new LineSegment {Point = new Point (0, ActualHeight)} Figure.Segments.Add (segment); break; case Direction.Down: figure.StartPoint = new Point (0,0); segment = new LineSegment {Point = new Point (ActualWidth, 0)}; figure.Segments.Add (segment) Segment = new LineSegment {Point = new Point (ActualWidth / 2, ActualHeight)}; figure.Segments.Add (segment); break;} _ pathElement.Data = geometry;}
The advantage of this approach is that it is easy to implement and compatible with WPF and UWP. The disadvantage is that the appearance of Path can only be modified through PathElementStyle. After all, it is not Shape, and it increases the level of VisualTree, which is not suitable for performance-sensitive situations.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.