बिजीइंडिएटर के बारे में हालिया पोस्ट के जवाब में इस समस्या के अपने अनुभव / दृष्टि को साझा करने का निर्णय लिया। मेरी राय में, लेख रोजगार नियंत्रण के संकेतक का एक सरल कार्यान्वयन प्रस्तुत करता है। अब कोई भी आदरणीय विकास कंपनियों से तैयार उत्पादों का उपयोग कर सकता है, लेकिन इस मामले में "लीक एब्स्ट्रेक्शन" की समस्या बहुत जरूरी हो जाती है। उनके लिए अप्राकृतिक तरीके से तैयार संकेतकों का उपयोग अनिवार्य रूप से विनाशकारी परिणाम की ओर ले जाता है। इसलिए, यह कल्पना करना बहुत महत्वपूर्ण है "यह कैसे काम करता है।"
Otma3ka
डब्ल्यू कोडिल, " बिजी इंडीकेटर " के बारे में एक पड़ोसी पोस्ट से प्रेरित होकर- भयंकर उत्साह के साथ, उन्होंने "बेस्ट प्रैक्टिस गाइड्स" को वापस देखे बिना कोड लिखा।
- वास्तव में, यह दिलचस्प था कि मैंने कितनी अच्छी तरह सबक सीखा और अपनी आंतरिक " 10k घड़ी " को अपडेट किया
- उपरोक्त और समय की एक भयावह कमी के कारण, कोड लालित्य के साथ चमकता नहीं है
- इसके अलावा, कोड सार्वभौमिक नहीं है; मौजूदा एप्लिकेशन आर्किटेक्चर में इसे एकीकृत करना मुश्किल हो सकता है
- लेकिन यह सरल और समझ में आता है (कम से कम मेरे लिए), और सबसे महत्वपूर्ण बात यह है कि इसमें कोई सुधार नहीं है [/ hehe]
समस्या का बयान
तो
हाँ, लेकिन ... दिया:
- मुख्य विंडो जिसमें डेटा प्रविष्टि का कुछ रूप रखा गया है

- विंडो में प्रपत्र BaseAdornableControl का एक उदाहरण है : UserControl (या वंशज) वर्ग, जिसमें सार्वजनिक संपत्ति है
- इस संपत्ति के सेटर में, व्यस्त संकेतक जुड़ा हुआ है / डिस्कनेक्ट किया गया है
- मुख्य विंडो के DataContext को डेमो ViewModel के उदाहरण का मूल्य सौंपा गया है ("और हम इस चर
को darling के साथ कॉल करेंगे" SimpleBusyAdornerDemoViewModel ) - ViewModel के पास एक bulinovy प्रॉपर्टी है IsBusy और इस प्रॉपर्टी के बदले जाने की स्थिति में Action [बूल] है
- मैं सादगी के लिए घटना से परेशान नहीं था (मैं एक अतिरिक्त हैंडलर वर्ग और उसके तर्क की घोषणा नहीं करना चाहता था)
- तर्क यह है: जब IsBusy मान को बदलते हैं, तो कार्रवाई [bool] IsBusyChanged ट्विच को एक तर्क के रूप में नए IsBusy मान के साथ
- एक्शन [बूल] का सब्सक्राइब करना IsBusyChanged BaseAdornableControl उदाहरण की BusyAdorner संपत्ति के लिए मान को या तो अशक्त (एडनर को डिस्कनेक्ट करने के लिए) या एक नॉन-जीरो वैल्यू (एडर्नर संलग्न) के लिए सेट करता है
- फिर से, सादगी के लिए, मैंने विंडो में एक बटन लगाया, जो ViewModel के IsBusy मूल्य को प्रभावित करता है, लेकिन हम आपके साथ जानते हैं कि ViewModel MUST DO IT के लिए, उदाहरण के लिए, जब एक वेब सेवा के लिए अनुरोध भेज रहा है और प्रतिक्रिया प्राप्त कर रहा है।
मुख्य खिड़की
<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 {
यहां सब कुछ सरल है। विंडो में वह प्रपत्र निहित है जिसे हम चिह्नित करना चाहते हैं। इसके नीचे एक बटन है, जो
व्यूमॉडल में
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);
यह समझा जाता है कि यह एक प्रकार का "ट्विस्ट" है,
जो डरावना स्मारकों का निर्माण करता है जो रोजगार को दर्शाता है। इस मामले में, तस्वीर स्थिर होगी, लेकिन
रोटेटट्रांसफॉर्म के कोण को अपडेट करने के लिए घूर्णी गतिशीलता के लिए पर्याप्त टाइमर नहीं है। यहां आप एनीमेशन के लिए कल्पना को वेंट दे सकते हैं। वैसे, आप 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 {
महत्वपूर्ण सूचना । एडोर्नर में लिपटे नियंत्रण को उतारने से पहले, एडोर्नर को पाप (मेमोरी लीक) से दूर करना आवश्यक है। 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) => {
वहाँ प्रस्तुत संकेतक अनिवार्य रूप से एक विशेष संवाद है जो उपयोगकर्ता को अतुल्यकालिक कार्य की प्रगति के बारे में सूचित करने के लिए डिज़ाइन किया गया है। यह डायलॉग पूरी विंडो / एप्लिकेशन पर एक किया जाता है। यहां प्रस्तुत संकेतक को उच्च मेमोरी खपत के डर के बिना प्रत्येक नियंत्रण के लिए अलग से लटका दिया जा सकता है। बस विभिन्न श्रेणियों।