winforms
इनहेरिटिंग नियंत्रण
खोज…
टिप्पणियों
नियंत्रण अन्य वर्गों की तरह ही प्राप्त होते हैं। घटनाओं से सावधान रहने के लिए केवल एक चीज है: आमतौर पर यह सुनिश्चित करने के लिए सलाह दी जाती है कि आप बेस इवेंट हैंडलर को अपने पास बुलाएं। मेरे अंगूठे का अपना नियम: यदि संदेह है, तो आधार घटना को कॉल करें।
आवेदन चौड़ी सेटिंग्स
अधिकांश डेवलपर साइटों के एक त्वरित पढ़ने से पता चलेगा कि WinForms को WPF से हीन माना जाता है। एक सबसे अक्सर उद्धृत कारणों में से एक पूरे आवेदन के "लुक-एंड-फील" में व्यापक रूप से परिवर्तन करने में माना जाता है।
वास्तव में यह WinForms में एक एप्लिकेशन का उत्पादन करने के लिए आश्चर्यजनक रूप से आसान है जो डिज़ाइन-टाइम और रन-टाइम दोनों में आसानी से कॉन्फ़िगर करने योग्य है, अगर आप बस मानक नियंत्रणों के उपयोग से बचते हैं और उनसे अपना खुद का व्युत्पन्न करते हैं।
उदाहरण के रूप में TextBox को लें। एक विंडोज़ एप्लिकेशन की कल्पना करना कठिन है जो किसी चरण या अन्य पर टेक्स्टबॉक्स के उपयोग के लिए कॉल नहीं करता है। इसलिए, अपने खुद के TextBox होने का हमेशा मतलब होगा। निम्नलिखित उदाहरण लें:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace StackOverflowDocumentation
{
public class SOTextBox : TextBox
{
public SOTextBox() : base()
{
base.BackColor = SOUserPreferences.BackColor;
base.ForeColor = SOUserPreferences.ForeColor;
}
protected override void OnEnter(EventArgs e)
{
base.BackColor = SOUserPreferences.FocusColor;
base.OnEnter(e);
}
protected override void OnLeave(EventArgs e)
{
base.BackColor = SOUserPreferences.BackColor;
base.OnLeave(e);
}
}
}
कई इनपुट बॉक्स के साथ, डेटा एंट्री फॉर्म में उपयोगकर्ताओं को सबसे अधिक उपयोगी चीजों में से एक है, जिसमें फोकस परिवर्तन के साथ बॉक्स का पृष्ठभूमि रंग है। दृश्यमान रूप से यह देखना आसान है, एक मानक ब्लिंकिंग ऊर्ध्वाधर कर्सर की तुलना में। उपरोक्त कोड एक TextBox प्रदान करता है जो ठीक यही करता है।
इस प्रक्रिया में यह एक स्थिर वर्ग के स्थिर गुणों का उपयोग करता है। मैं नीचे से एक अर्क देता हूँ:
using System;
using System.Threading;
using Microsoft.Win32;
using System.Globalization;
using System.Data;
using System.Drawing;
namespace StackOverflowDocumentation
{
public class SOUserPreferences
{
private static string language;
private static string logPath;
private static int formBackCol;
private static int formForeCol;
private static int backCol;
private static int foreCol;
private static int focusCol;
static SOUserPreferences()
{
try
{
RegistryKey HKCU = Registry.CurrentUser;
RegistryKey kSOPrefs = HKCU.OpenSubKey("SOPrefs");
if (kSOPrefs != null)
{
language = kSOPrefs.GetValue("Language", "EN").ToString();
logPath = kSOPrefs.GetValue("LogPath", "c:\\windows\\logs\\").ToString();
formForeCol = int.Parse(kSOPrefs.GetValue("FormForeColor", "-2147483630").ToString());
formBackCol = int.Parse(kSOPrefs.GetValue("FormBackColor", "-2147483633").ToString());
foreCol = int.Parse(kSOPrefs.GetValue("ForeColor", "-2147483640").ToString());
backCol = int.Parse(kSOPrefs.GetValue("BackColor", "-2147483643").ToString());
focusCol = int.Parse(kSOPrefs.GetValue("FocusColor", "-2147483643").ToString());
}
else
{
language = "EN";
logPath = "c:\\windows\\logs\\";
formForeCol = -2147483630;
formBackCol = -2147483633;
foreCol = -2147483640;
backCol = -2147483643;
focusCol = -2147483643;
}
}
catch (Exception ex)
{
//handle exception here;
}
}
public static string Language
{
get
{
return language;
}
set
{
language = value;
}
}
public static string LogPath
{
get
{
return logPath;
}
set
{
logPath = value;
}
}
public static Color FormBackColor
{
get
{
return ColorTranslator.FromOle(formBackCol);
}
set
{
formBackCol = ColorTranslator.ToOle(value);
}
}
public static Color FormForeColor
{
get
{
return ColorTranslator.FromOle(formForeCol);
}
set
{
formForeCol = ColorTranslator.ToOle(value);
}
}
public static Color BackColor
{
get
{
return ColorTranslator.FromOle(backCol);
}
set
{
backCol = ColorTranslator.ToOle(value);
}
}
public static Color ForeColor
{
get
{
return ColorTranslator.FromOle(foreCol);
}
set
{
foreCol = ColorTranslator.ToOle(value);
}
}
public static Color FocusColor
{
get
{
return ColorTranslator.FromOle(focusCol);
}
set
{
focusCol = ColorTranslator.ToOle(value);
}
}
}
}
यह वर्ग गुणों को बनाए रखने के लिए Windows रजिस्ट्री का उपयोग करता है, लेकिन यदि आप चाहें तो आप डेटाबेस या सेटिंग्स फ़ाइल का उपयोग कर सकते हैं। इस तरह से एक स्थिर वर्ग का उपयोग करने का लाभ यह है कि आवेदन में व्यापक परिवर्तन न केवल डिज़ाइन-टाइम पर किए जा सकते हैं, बल्कि रन-टाइम पर उपयोगकर्ता द्वारा भी किए जा सकते हैं। मैं हमेशा अपने अनुप्रयोगों में एक फॉर्म शामिल करता हूं जिससे उपयोगकर्ता पसंदीदा मूल्यों को बदल सकता है। सेव फंक्शन न केवल रजिस्ट्री (या डेटाबेस आदि) में सेव होता है, बल्कि रन-टाइम पर भी स्टैटिक क्लास में प्रॉपर्टीज को बदल देता है। ध्यान दें कि स्थिर वर्ग के स्थिर गुण स्थिर नहीं होते हैं; इस अर्थ में उन्हें अनुप्रयोग विस्तृत चर के रूप में माना जा सकता है। इसका अर्थ है कि सहेजे जा रहे परिवर्तनों के बाद खोला गया कोई भी रूप तुरंत सहेजे गए परिवर्तनों से प्रभावित होगा।
आप आसानी से अन्य अनुप्रयोग विस्तृत गुणों के बारे में सोच पाएंगे जो आप उसी तरह से कॉन्फ़िगर करना चाहेंगे। फ़ॉन्ट्स एक और बहुत अच्छा उदाहरण हैं।
NumberBox
अक्सर आप एक इनपुट बॉक्स रखना चाहेंगे जो केवल नंबर लेता है। मानक नियंत्रण से प्राप्त करके फिर से यह आसानी से हासिल किया जाता है, उदाहरण के लिए:
using System;
using System.Windows.Forms;
using System.Globalization;
namespace StackOverflowDocumentation
{
public class SONumberBox : SOTextBox
{
private int decPlaces;
private int extraDecPlaces;
private bool perCent;
private bool useThouSep = true;
private string decSep = ".";
private string thouSep = ",";
private double numVal;
public SONumberBox() : base()
{
}
public bool PerCent
{
get
{
return perCent;
}
set
{
perCent = value;
}
}
public double Value
{
get
{
return numVal;
}
set
{
numVal = value;
if (perCent)
{
double test = numVal * 100.0;
this.Text = FormatNumber(test) + "%";
}
else
{
this.Text = FormatNumber(value);
}
}
}
public bool UseThousandSeparator
{
get
{
return useThouSep;
}
set
{
useThouSep = value;
}
}
public int DecimalPlaces
{
get
{
return decPlaces;
}
set
{
decPlaces = value;
}
}
public int ExtraDecimalPlaces
{
get
{
return extraDecPlaces;
}
set
{
extraDecPlaces = value;
}
}
protected override void OnTextChanged(EventArgs e)
{
string newVal = this.Text;
int len = newVal.Length;
if (len == 0)
{
return;
}
bool neg = false;
if (len > 1)
{
if (newVal.Substring(0, 1) == "-")
{
newVal = newVal.Substring(1, len - 1);
len = newVal.Length;
neg = true;
}
}
double val = 1.0;
string endChar = newVal.Substring(newVal.Length - 1);
switch (endChar)
{
case "M":
case "m":
if (len > 1)
{
val = double.Parse(newVal.Substring(0, len - 1)) * 1000000.0;
}
else
{
val *= 1000000.0;
}
if (neg)
{
val = -val;
}
this.Text = FormatNumber(val);
break;
case "T":
case "t":
if (len > 1)
{
val = double.Parse(newVal.Substring(0, len - 1)) * 1000.0;
}
else
{
val *= 1000.0;
}
if (neg)
{
val = -val;
}
this.Text = FormatNumber(val);
break;
}
base.OnTextChanged(e);
}
protected override void OnKeyPress(KeyPressEventArgs e)
{
bool handled = false;
switch (e.KeyChar)
{
case '-':
if (this.Text.Length == 0)
{
break;
}
else if (this.SelectionStart == 0)
{
//negative being inserted first
break;
}
else
{
handled = true;
break;
}
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '0':
case (char)Keys.Back:
break;
case 'M':
case 'm':
case 'T':
case 't':
case '%':
//check last pos
int l = this.Text.Length;
int sT = this.SelectionStart;
int sL = this.SelectionLength;
if ((sT + sL) != l)
{
handled = true;
}
break;
default:
string thisChar = e.KeyChar.ToString();
if (thisChar == decSep)
{
char[] txt = this.Text.ToCharArray();
for (int i = 0; i < txt.Length; i++)
{
if (txt[i].ToString() == decSep)
{
handled = true;
break;
}
}
break;
}
else if (thisChar != thouSep)
{
handled = true;
}
break;
}
if (!handled)
{
base.OnKeyPress(e);
}
else
{
e.Handled = true;
}
}
protected override void OnLeave(EventArgs e)
{
string tmp = this.Text;
if (tmp == "")
{
tmp = "0";
numVal = NumberLostFocus(ref tmp);
this.Text = tmp;
}
if (tmp.Substring(tmp.Length - 1) == "%")
{
tmp = tmp.Substring(0, tmp.Length - 1);
numVal = 0.0;
numVal = NumberLostFocus(ref tmp) / 100.0;
double test = numVal * 100.0;
this.Text = FormatNumber(test) + "%";
}
else if (perCent)
{
numVal = NumberLostFocus(ref tmp);
double test = numVal * 100.0;
this.Text = FormatNumber(test) + "%";
}
else
{
numVal = NumberLostFocus(ref tmp);
this.Text = tmp;
}
base.OnLeave(e);
}
private string FormatNumber(double amount)
{
NumberFormatInfo nF = new NumberFormatInfo();
nF.NumberDecimalSeparator = decSep;
nF.NumberGroupSeparator = thouSep;
string decFormat;
if (useThouSep)
{
decFormat = "#,##0";
}
else
{
decFormat = "#0";
}
if (decPlaces > 0)
{
decFormat += ".";
for (int i = 0; i < decPlaces; i++)
{
decFormat += "0";
}
if (extraDecPlaces > 0)
{
for (int i = 0; i < extraDecPlaces; i++)
{
decFormat += "#";
}
}
}
else if (extraDecPlaces > 0)
{
decFormat += ".";
for (int i = 0; i < extraDecPlaces; i++)
{
decFormat += "#";
}
}
return (amount.ToString(decFormat, nF));
}
private double NumberLostFocus(ref string amountBox)
{
if (amountBox.Substring(0, 1) == decSep)
amountBox = "0" + amountBox;
NumberFormatInfo nF = new NumberFormatInfo();
nF.NumberDecimalSeparator = decSep;
nF.NumberGroupSeparator = thouSep;
try
{
double d = 0.0;
int l = amountBox.Length;
if (l > 0)
{
char[] c = amountBox.ToCharArray();
char endChar = c[l - 1];
switch (endChar)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
stripNonNumerics(ref amountBox);
d = Double.Parse(amountBox, nF);
break;
}
case 'm':
case 'M':
{
if (amountBox.Length == 1)
d = 1000000.0;
else
{
string s = amountBox.Substring(0, l - 1);
stripNonNumerics(ref s);
d = Double.Parse(s, nF) * 1000000.0;
}
break;
}
case 't':
case 'T':
{
if (amountBox.Length == 1)
d = 1000.0;
else
{
string s = amountBox.Substring(0, l - 1);
stripNonNumerics(ref s);
d = Double.Parse(s, nF) * 1000.0;
}
break;
}
default:
{
//remove offending char
string s = amountBox.Substring(0, l - 1);
if (s.Length > 0)
{
stripNonNumerics(ref s);
d = Double.Parse(s, nF);
}
else
d = 0.0;
break;
}
}
}
amountBox = FormatNumber(d);
return (d);
}
catch (Exception e)
{
//handle exception here;
return 0.0;
}
}
private void stripNonNumerics(ref string amountBox)
{
bool dSFound = false;
char[] tmp = decSep.ToCharArray();
char dS = tmp[0];
string cleanNum = "";
int l = amountBox.Length;
if (l > 0)
{
char[] c = amountBox.ToCharArray();
for (int i = 0; i < l; i++)
{
char b = c[i];
switch (b)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
cleanNum += b;
break;
case '-':
if (i == 0)
cleanNum += b;
break;
default:
if ((b == dS) && (!dSFound))
{
dSFound = true;
cleanNum += b;
}
break;
}
}
}
amountBox = cleanNum;
}
}
संख्याओं के लिए इनपुट को प्रतिबंधित करने के साथ-साथ इस वर्ग में कुछ विशेष विशेषताएं हैं। यह संख्या के दोहरे मूल्य का प्रतिनिधित्व करने के लिए एक संपत्ति मूल्य को उजागर करता है, यह पाठ को प्रारूपित करता है, वैकल्पिक रूप से हजार विभाजकों के साथ, और यह बड़ी संख्या में शॉर्ट-हैंड एंट्री प्रदान करता है: 10M छुट्टी पर 10,000,000.00 तक फैलता है (दशमलव स्थानों की संख्या संपत्ति है )। संक्षिप्तता के लिए, दशमलव और हजार विभाजकों को हार्ड-कोड किया गया है। एक उत्पादन प्रणाली में, ये भी उपयोगकर्ता प्राथमिकताएं हैं।