मैं कैसे बिजी करूंगा

बिजीइंडिएटर के बारे में हालिया पोस्ट के जवाब में इस समस्या के अपने अनुभव / दृष्टि को साझा करने का निर्णय लिया। मेरी राय में, लेख रोजगार नियंत्रण के संकेतक का एक सरल कार्यान्वयन प्रस्तुत करता है। अब कोई भी आदरणीय विकास कंपनियों से तैयार उत्पादों का उपयोग कर सकता है, लेकिन इस मामले में "लीक एब्स्ट्रेक्शन" की समस्या बहुत जरूरी हो जाती है। उनके लिए अप्राकृतिक तरीके से तैयार संकेतकों का उपयोग अनिवार्य रूप से विनाशकारी परिणाम की ओर ले जाता है। इसलिए, यह कल्पना करना बहुत महत्वपूर्ण है "यह कैसे काम करता है।"

Otma3ka




समस्या का बयान


तो हाँ, लेकिन ... दिया:


मुख्य खिड़की


<Window x:Class="MyBusyAdorner.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:views="clr-namespace:MyBusyAdorner.Views" xmlns:adorners="clr-namespace:MyBusyAdorner.Adorners" Title="MainWindow" Height="350" Width="525"> <Grid> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <views:BaseAdornableControl x:Name="AdornableControl" BusyAdorner="{x:Null}" Margin="15"/> <Button Content="Attach/Detach" Grid.Row="1" Click="Button_Click"/> </Grid> </Window> 

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using MyBusyAdorner.ViewModels; using MyBusyAdorner.Adorners; namespace MyBusyAdorner { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { private SimpleBusyAdornerDemoViewModel _viewModel; public MainWindow() { InitializeComponent(); DataContext = _viewModel = new SimpleBusyAdornerDemoViewModel(); _viewModel.IsBusyChanged = new Action<bool>((newValue) => { AttachDetachBusyAdorner(newValue); }); } private void AttachDetachBusyAdorner(bool isBusy) { AdornableControl.BusyAdorner = isBusy ? new BusyAdorner(AdornableControl) : null; } private void Button_Click(object sender, RoutedEventArgs e) { _viewModel.IsBusy = !_viewModel.IsBusy; } } } 

यहां सब कुछ सरल है। विंडो में वह प्रपत्र निहित है जिसे हम चिह्नित करना चाहते हैं। इसके नीचे एक बटन है, जो व्यूमॉडल में IsBusy संपत्ति के मूल्य को बदलता है। जैसा कि मैंने पहले ही लिखा था, यह बटन किसी कार्य (एसिंक्रोनस) की शुरुआत और अंत का अनुकरण करता है। ViewModel के साथ अतुल्यकालिक कार्य के इंटरैक्शन का तर्क कैसे लागू किया जाता है, इस मामले में महत्वपूर्ण नहीं है। हम मान लेंगे कि TPL पुस्तकालय का उपयोग किया जाता है (वैसे, यह मेरा mcDonnalds है - 'क्योंकि मैं Lovin हूँ ...)। मुख्य विंडो के डिजाइनर में, एक्शन के लिए एक IsBusy परिवर्तन सदस्यता बनाई गई है। इस मामले में, केवल एक हैंडलर है, इसलिए मैं एक्शन का उपयोग कर सकता हूं। अन्यथा, एक प्रतिनिधि को साथ नहीं भेजा जा सकता था। तो, हैंडलर एडोर्नटेबलकंट्रोल के बिजी एडोर्नर मूल्य को सेट करता है: संकेतक को डिस्कनेक्ट करने के लिए अशक्त, संलग्न करने के लिए शून्य नहीं।

BusyAdorner


 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Documents; using System.Windows; using System.Windows.Media; namespace MyBusyAdorner.Adorners { public class BusyAdorner : Adorner { public BusyAdorner(UIElement adornedElement) : base(adornedElement) { } protected override void OnRender(DrawingContext drawingContext) { var adornedControl = this.AdornedElement as FrameworkElement; if (adornedControl == null) return; Rect rect = new Rect(0,0, adornedControl.ActualWidth, adornedControl.ActualHeight); // Some arbitrary drawing implements. SolidColorBrush renderBrush = new SolidColorBrush(Colors.Green); renderBrush.Opacity = 0.2; Pen renderPen = new Pen(new SolidColorBrush(Colors.Navy), 1.5); double renderRadius = 5.0; double dist = 15; double cntrX = rect.Width / 2; double cntrY = rect.Height / 2; double left = cntrX - dist; double right = cntrX + dist; double top = cntrY - dist; double bottom = cntrY + dist; // Draw four circles near to center. drawingContext.PushTransform(new RotateTransform(45, cntrX, cntrY)); drawingContext.DrawEllipse(renderBrush, renderPen, new Point { X = left, Y = top}, renderRadius, renderRadius); drawingContext.DrawEllipse(renderBrush, renderPen, new Point { X = right, Y = top }, renderRadius, renderRadius); drawingContext.DrawEllipse(renderBrush, renderPen, new Point { X = right, Y = bottom }, renderRadius, renderRadius); drawingContext.DrawEllipse(renderBrush, renderPen, new Point { X = left, Y = bottom }, renderRadius, renderRadius); } } } 

यह समझा जाता है कि यह एक प्रकार का "ट्विस्ट" है, जो डरावना स्मारकों का निर्माण करता है जो रोजगार को दर्शाता है। इस मामले में, तस्वीर स्थिर होगी, लेकिन रोटेटट्रांसफॉर्म के कोण को अपडेट करने के लिए घूर्णी गतिशीलता के लिए पर्याप्त टाइमर नहीं है। यहां आप एनीमेशन के लिए कल्पना को वेंट दे सकते हैं। वैसे, आप TPL से समान कार्य का उपयोग तस्वीर के रोटेशन के कोण को सुचारू रूप से बदलने के लिए कर सकते हैं (HMM ... टास्क को गेम लूप के रूप में करना चाहिए। क्या मुझे कोशिश करनी चाहिए! )।
तो, यह इस तरह दिखेगा:

भगवान नहीं जानता कि क्या, लेकिन अवधारणा के एक प्रदर्शन के रूप में नीचे आता है।

BaseAdornableControl


 <!--    ... ..     --> 

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using MyBusyAdorner.Adorners; namespace MyBusyAdorner.Views { /// <summary> /// Interaction logic for BaseAdornableControl.xaml /// </summary> public partial class BaseAdornableControl : UserControl { #region [Fields] //private List<Adorner> _adorners = new List<Adorner>(); private BusyAdorner _busyAdorner; #endregion [/Fields] #region [Properties] public BusyAdorner BusyAdorner { get { return _busyAdorner; } set { DetachBusyAdorner(); _busyAdorner = value; if (value != null) { AttachBusyAdorner(); } } } private void AttachBusyAdorner() { if (_busyAdorner == null) return; var adornerLayer = AdornerLayer.GetAdornerLayer(this); adornerLayer.Add(_busyAdorner); } private void DetachBusyAdorner() { var adornerLayer = AdornerLayer.GetAdornerLayer(this); if (adornerLayer != null && _busyAdorner != null) { adornerLayer.Remove(_busyAdorner); } } #endregion [/Properties] public BaseAdornableControl() { InitializeComponent(); this.Unloaded += new RoutedEventHandler(BaseAdornableControl_Unloaded); } void BaseAdornableControl_Unloaded(object sender, RoutedEventArgs e) { DetachBusyAdorner(); } } } 

महत्वपूर्ण सूचना । एडोर्नर में लिपटे नियंत्रण को उतारने से पहले, एडोर्नर को पाप (मेमोरी लीक) से दूर करना आवश्यक है। AdornerLayer का तर्क काफी जटिल है, और सतर्कता के नुकसान के साथ, आप रेक कर सकते हैं। इसलिए मैंने आपको चेतावनी दी ...

SimpleBusyAdornerDemoViewModel


 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel; namespace MyBusyAdorner.ViewModels { public class SimpleBusyAdornerDemoViewModel : INotifyPropertyChanged { #region [Fields] private bool _isBusy; #endregion [/Fields] #region [Properties] public bool IsBusy { get { return _isBusy; } set { if (value != _isBusy) { _isBusy = value; RaisePropertyChanged("IsBusy"); RaiseIsBusyChanged(); } } } public Action<bool> IsBusyChanged { get; set; } #endregion [/Properties] #region [Private Methods] private void RaiseIsBusyChanged() { if (IsBusyChanged != null) { IsBusyChanged(_isBusy); } } #endregion [/Private Methods] #region [INotifyPropertyChanged] public event PropertyChangedEventHandler PropertyChanged; private void RaisePropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } #endregion [/INotifyPropertyChanged] } } 

एमवीवीएम पैटर्न से परिचित लोगों के लिए कुछ भी विशेष नहीं है, सिवाय घटना के बजाय एक्शन के साथ "डब्ल्यूटीएफ-कोड" के अलावा।

अतिरिक्त सुविधा - BusyAdornerManager


 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections.ObjectModel; using MyBusyAdorner.Adorners; using System.Windows; using System.Windows.Documents; namespace MyBusyAdorner.Services { public sealed class BusyAdornerManager { #region [Fieds] private List<BusyAdorner> _adorners; #endregion [/Fieds] #region [Public Methods] public void AddBusyAdorner(UIElement adornedElement) { if (adornedElement == null) return; var adorner = new BusyAdorner(adornedElement); _adorners.Add(adorner); } public void RemoveAllAdorners(UIElement adornedElement) { if (adornedElement == null) return; var adornerLayer = AdornerLayer.GetAdornerLayer(adornedElement); foreach (var adorner in adornerLayer.GetAdorners(adornerLayer)) { adornerLayer.Remove(adorner); } } #endregion [/Public Methods] #region Singleton private static volatile BusyAdornerManager instance; private static object syncRoot = new Object(); private BusyAdornerManager() { } public static BusyAdornerManager Instance { get { if (instance == null) { lock (syncRoot) { if (instance == null) instance = new BusyAdornerManager(); } } return instance; } } #endregion } } 

यह एक ऐसी सेवा है जिसे मनमाने नियंत्रणों पर लटके हुए श्रंगार की सुविधा के लिए बनाया गया है। इसके अलावा kakulka - यह एक सिंगलटन नहीं बनाया जा सकता है, लेकिन सिर्फ एक स्थिर वर्ग, और एड्रेनों की सूची अभी भी इसके लायक है।

निष्कर्ष


इस बात पर फैलें कि मैं कहाँ और किस बिंदु को नहीं देख रहा हूँ, और मैं नहीं चाहता, खुलकर, इस तरह के कुचक्र के साथ खिलवाड़ करना चाहता हूँ। मेरे लिए, यह पोस्ट एक स्निपेट है, विचारों / ज्ञान को क्रम में रखने का प्रयास है, साथ ही साथ हेबव्यू बोर्ड के लिए एक टिकट भी है। लेकिन शायद किसी को यह उपयोगी लगेगा। इसलिए हम अपने स्वास्थ्य की आलोचना करते हैं, बस "कोड-स्टाइल गाइड" के बारे में होलीवर्स के बिना जाने दें ... ठीक है?

युपीडी


वंशानुक्रम उपरि के मुद्दे पर ... एक प्रपत्र देखें आमतौर पर एक UserControl है। क्या XAML में लिखना संभव है, उदाहरण के लिए, UserControlEx या UserControl के बजाय एक ही BaseAdornableControl - एक बड़ा ओवरहेड?

विशुद्ध रूप से MVVM दृष्टिकोण का उपयोग करने के सवाल पर ... BaseAdornableControl में DependencyProperty को जोड़ना और इसे IsBusy ViewModel से बाँधना आसान है। इस संपत्ति को बदलने के लिए हैंडलर में, वही करें जो मैंने बाहर से ऑर्डर किया था। यह 3 पार्टी उत्पाद की आंतरिक संपत्ति के लिए एक पलटा के साथ बैसाखी के निर्माण की तुलना में बहुत अधिक विश्वसनीय है। कौन जानता है कि तीसरे पक्ष के डेवलपर्स खुद के अंदर बदलाव के बारे में क्या सोचेंगे?

एड्नर को सीधे ViewModel प्रॉपर्टी से बाँधने के मुद्दे पर ... जैसा कि मैंने कमेंट्री में लिखा है, मुझे इसमें DependencyProperty रखना होगा, और इसके लिए, Adner को फ्रेमवर्क से विरासत में प्राप्त करना होगा, उदाहरण के लिए। और यह एक बहुत ही गंभीर ओवरहेड होगा, खासकर अगर एडोर्न हर समय स्मृति में लटका रहता है।
मनोरंजन के लिए विज़िफ़ेयर कोड देखें। या कम से कम SNOOP'om पेड़ BarChart'a के माध्यम से चलते हैं। वहां, चार्ट में प्रत्येक बार के लिए, एक या दो मध्यवर्ती कैनवस बनाए जाते हैं। इसके अलावा, DataPoint फ्रेमवर्क से विरासत में मिला है, या तो DataPoint को किसी चीज़ से बाँधने की क्षमता है, या रंग गुण सेट करने के लिए (जो, वैसे, Color नहीं है, लेकिन ब्रश से कोई मतलब नहीं है)। और मजाक यह है कि ये डेटा पॉइंट्स, वे फ्रेमवर्क हैं, चार्ट में कैनवास पर समाप्त होते हैं। उन पर एक और फ्रेमवर्क के संग्रह को नए सिरे से बनाया जाता है, जिसे खींचा जाता है। नतीजतन, विज़िफ़ायर चार्ट 600+ तत्वों पर पहले से ही ब्रेक लगाना शुरू कर देता है। तुलना के लिए: डायनामिक डेटा डिस्प्ले -> लाइन चार्ट -> 60k एलिमेंट्स (विशेषकर चिकने ग्राफिक्स के साथ) -> यह सामान्य रूप से खींचा जाता है।
इसलिए, ViewModel को सीधे बाँधने के निर्णय से पूरी तरह से अनावश्यक ओवरहेड हो जाएगा।

UPD2


टूलकिट इंडिकेटर के उपयोग के सवाल पर ...
टिप्पणियाँ हैं ... पढ़ें उदाहरण के लिए, कोड:
 BackgroundWorker worker = new BackgroundWorker(); worker.DoWork += (o, ea) => { //long-running-process code System.Threading.Thread.Sleep(10000); DispatchService.Dispatch((Action)(() => { //update the UI code goes here // ... })); }; worker.RunWorkerCompleted += (o, ea) => { this.ResetIsBusy(); //here the BusyIndicator.IsBusy is set to FALSE }; this.SetIsBusy(); //here the BusyIndicator.IsBusy is set to TRUE worker.RunWorkerAsync(); 

वहाँ प्रस्तुत संकेतक अनिवार्य रूप से एक विशेष संवाद है जो उपयोगकर्ता को अतुल्यकालिक कार्य की प्रगति के बारे में सूचित करने के लिए डिज़ाइन किया गया है। यह डायलॉग पूरी विंडो / एप्लिकेशन पर एक किया जाता है। यहां प्रस्तुत संकेतक को उच्च मेमोरी खपत के डर के बिना प्रत्येक नियंत्रण के लिए अलग से लटका दिया जा सकता है। बस विभिन्न श्रेणियों।

Source: https://habr.com/ru/post/In142243/


All Articles