2010-05-11 15 views
22

पर नियंत्रण जोड़ें मैं उपयोगकर्ता नियंत्रक को गतिशील रूप से (प्रोग्रामेटिक रूप से) नियंत्रण जोड़ने की कोशिश कर रहा हूं। मुझे अपने बिजनेस लेयर (डेटाबेस से पुनर्प्राप्त) से ऑब्जेक्ट्स की एक सामान्य सूची मिलती है, और प्रत्येक ऑब्जेक्ट के लिए, मैं एक लेबल जोड़ना चाहता हूं, और WPF UserControl में टेक्स्टबॉक्स जोड़ना चाहता हूं और स्थिति को देखने के लिए स्थिति और चौड़ाई निर्धारित करना चाहता हूं, और उम्मीद है कि WPF प्रमाणीकरण क्षमताओं का लाभ उठाएं। यह ऐसा कुछ है जो विंडोज फॉर्म प्रोग्रामिंग में आसान होगा लेकिन मैं WPF के लिए नया हूं। कैसे मैं यह कर (प्रश्नों के लिए टिप्पणी देखें) है कहो यह मेरा वस्तु है:प्रोग्रामेटिक रूप से डब्ल्यूपीएफ फॉर्म

public void createControls() { 
    List<Field> fields = businessObj.getFields(); 

    Label label = null; 
    TextBox textbox = null; 

    foreach (Field field in fields) { 
     label = new Label(); 
     // HOW TO set text, x and y (margin), width, validation based upon object? 
     // i have tried this without luck: 
     // Binding b = new Binding("Name"); 
     // BindingOperations.SetBinding(label, Label.ContentProperty, b); 
     MyGrid.Children.Add(label); 

     textbox = new TextBox(); 
     // ??? 
     MyGrid.Children.Add(textbox); 
    } 
    // databind? 
    this.DataContext = fields; 
} 

उत्तर

21

ठीक है, दूसरी बार आकर्षण है। आपके लेआउट स्क्रीनशॉट के आधार पर, मैं तुरंत अनुमान लगा सकता हूं कि आपको जो चाहिए वह WrapPanel है, एक लेआउट पैनल जो आइटम को किनारे तक पहुंचने तक भरने की अनुमति देता है, जिस बिंदु पर शेष आइटम अगली पंक्ति पर बहती हैं। लेकिन आप अभी भी ItemsControl का उपयोग करना चाहते हैं ताकि आप डेटा-बाध्यकारी और गतिशील पीढ़ी के सभी लाभ प्राप्त कर सकें। तो इसके लिए हम ItemsControl.ItemsPanel संपत्ति का उपयोग करने जा रहे हैं, जो हमें पैनल को निर्दिष्ट करने की अनुमति देता है जिसमें वस्तुओं को रखा जाएगा। के कोड-पीछे फिर से शुरू करते हैं:

public partial class Window1 : Window 
{ 
    public ObservableCollection<Field> Fields { get; set; } 

    public Window1() 
    { 
     InitializeComponent(); 

     Fields = new ObservableCollection<Field>(); 
     Fields.Add(new Field() { Name = "Username", Length = 100, Required = true }); 
     Fields.Add(new Field() { Name = "Password", Length = 80, Required = true }); 
     Fields.Add(new Field() { Name = "City", Length = 100, Required = false }); 
     Fields.Add(new Field() { Name = "State", Length = 40, Required = false }); 
     Fields.Add(new Field() { Name = "Zipcode", Length = 60, Required = false }); 

     FieldsListBox.ItemsSource = Fields; 
    } 
} 

public class Field 
{ 
    public string Name { get; set; } 
    public int Length { get; set; } 
    public bool Required { get; set; } 
} 

ज्यादा नहीं यहां से बदल गया है, लेकिन मैं नमूना क्षेत्रों बेहतर अपने उदाहरण से मिलान करने के संपादित किया है। अब हम जहां जादू Window के लिए XAML happens- को देखो:

<Window x:Class="DataBoundFields.Window1" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:local="clr-namespace:DataBoundFields" 
Title="Window1" Height="200" Width="300"> 
<Window.Resources> 
    <local:BoolToVisibilityConverter x:Key="BoolToVisConverter"/> 
</Window.Resources> 
<Grid> 
    <ListBox x:Name="FieldsListBox"> 
     <ListBox.ItemTemplate> 
      <DataTemplate> 
       <StackPanel Orientation="Horizontal"> 
        <Label Content="{Binding Name}" VerticalAlignment="Center"/> 
        <TextBox Width="{Binding Length}" Margin="5,0,0,0"/> 
        <Label Content="*" Visibility="{Binding Required, Converter={StaticResource BoolToVisConverter}}"/> 
       </StackPanel> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
     <ListBox.ItemsPanel> 
      <ItemsPanelTemplate> 
       <WrapPanel Orientation="Horizontal" 
          Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=ActualHeight}" 
          Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=ActualWidth}"/> 
      </ItemsPanelTemplate> 
     </ListBox.ItemsPanel> 
    </ListBox> 
</Grid> 

सबसे पहले, आप देखेंगे कि ItemTemplate थोड़ा बदल गया है। लेबल अभी भी नाम संपत्ति से जुड़ा हुआ है, लेकिन अब टेक्स्टबॉक्स चौड़ाई लंबाई संपत्ति से जुड़ी है (इसलिए आप अलग-अलग लंबाई के टेक्स्टबॉक्स प्राप्त कर सकते हैं)। इसके अलावा, मैंने किसी भी फ़ील्ड में एक "*" जोड़ा है जो एक सरल BoolToVisibilityConverter (जिसे आप कहीं भी कोड पा सकते हैं, और मैं यहां पोस्ट नहीं करूंगा) का उपयोग कर आवश्यक है।

मुख्य बात सूचना के लिए हमारे ListBox की ItemsPanel संपत्ति में एक WrapPanel का उपयोग है। यह ListBox बताता है कि जो भी आइटम उत्पन्न करता है उसे क्षैतिज लिपटे लेआउट में धक्का दिया जाना चाहिए (यह आपके स्क्रीनशॉट से मेल खाता है)। इस काम को और भी बेहतर बनाता है कि पैनल पर ऊंचाई और चौड़ाई बाध्यकारी है- यह क्या कहता है, "इस पैनल को मेरी मूल विंडो के समान आकार बनाएं।" इसका मतलब है कि जब मैं Window का आकार बदलता हूं, तो WrapPanel तदनुसार इसके आकार को समायोजित करता है, जिसके परिणामस्वरूप वस्तुओं के लिए बेहतर लेआउट होता है। यहाँ दो स्क्रीनशॉट इस का प्रदर्शन:

alt text http://img156.imageshack.us/img156/6849/wrappanelfields.png

alt text http://img12.imageshack.us/img12/2426/wrappanelfields2.png

+0

+1, लेकिन मुझे लगता है कि ओपी लंबाई चाहता था और इनपुट को बाधित करने के लिए आवश्यक था। –

+0

बेशक, लेकिन मुझे यकीन नहीं है कि वह वास्तव में उन बाधाओं का उपयोग कैसे करना चाहता है, इसलिए मैंने इसे बिना छोड़ा। – Charlie

+0

परेशानी है- और शायद मैं परिवर्तनीय नाम "माईग्रिड" का उपयोग करके मामलों को भ्रमित कर रहा हूं- मैं डेटाग्रिड नहीं, पर जोड़ रहा हूं। यह डेटा प्रविष्टि फ़ॉर्म है जिसे मुझे एक विशिष्ट क्रम में बाहर करना है। 3 लेबल हो सकते हैं/टेक्स्टबॉक्स के साथ टेक्स्टबॉक्स संयोजन, एक पंक्ति पर अलग-अलग लंबाई, और अगली पंक्ति पर 10। इस फ़ॉर्म के विभिन्न संस्करण हैं, यही कारण है कि फ़ील्ड डेटाबेस से लोड हो जाते हैं, और मैं इसे गतिशील क्यों कहता हूं। इसलिए यह नहीं है डेटाग्रिड लेआउट में अच्छी तरह से फिट करें और यही कारण है कि मैं उन्हें गतिशील रूप से बनाने की कोशिश कर रहा था। क्या मेरे पास ऑब्जेक्ट में एक और फ़ील्ड है - LastFieldOnLine नई लाइन – user210757

15
:

public class Field { 
    public string Name { get; set; } 
    public int Length { get; set; } 
    public bool Required { get; set; } 
} 
तब मेरे WPF UserControl में

, मैं एक लेबल और प्रत्येक वस्तु के लिए पाठ बॉक्स बनाने के लिए कोशिश कर रहा हूँ

इस तरह के नियंत्रण जोड़ने की सिफारिश नहीं है। डब्ल्यूपीएफ में आप आदर्श रूप से क्या करते हैं, एक सूची बॉक्स (या आइटम नियंत्रण) डालना है और अपने व्यापार ऑब्जेक्ट संग्रह को आइटम्स कंट्रोल.इटेम्ससोर्स प्रॉपर्टी के रूप में बांधना है। अब अपने डेटा ऑब्जेक्ट प्रकार के लिए एक्सएएमएल में डेटा टेम्पलेट को परिभाषित करें और आप जाने के लिए अच्छे हैं, यह डब्ल्यूपीएफ का जादू है।

लोग एक विनफॉर्म पृष्ठभूमि से आते हैं जो आपके द्वारा वर्णित तरीके से करते हैं और जो WPF में सही तरीका नहीं है।

+6

+1। बहुत कम चीजें हैं जिनके बारे में मैं कहना चाहता हूं, स्पष्ट रूप से, "यह सिर्फ गलत है।" नियमित अभिव्यक्ति के साथ एक्सएमएल पार्सिंग एक है। WPF अनुप्रयोगों में WinForms तकनीकों का उपयोग करना एक और है। –

+0

आमेन। --------- –

7

मैं सवाल सीधे जवाब देने की खातिर चार्ली और Jobi के जवाब सुनने के लिए, लेकिन चाहते हैं ... (नियंत्रण और मैन्युअल रूप से स्थिति को कैसे जोड़ें उन्हें।)

Grid के बजाय Canvas नियंत्रण का उपयोग करें। कैनवस नियंत्रण को एक अनंत मात्रा में स्थान देते हैं, और आपको उन्हें मैन्युअल रूप से स्थिति देने की अनुमति देते हैं। यह स्थिति का ट्रैक रखने के लिए संलग्न गुणों का उपयोग करता है। कोड में, यह तो ऐसा दिखाई देगा:

var tb = new TextBox(); 
myCanvas.Children.Add(tb); 
tb.Width = 100; 
Canvas.SetLeft(tb, 50); 
Canvas.SetTop(tb, 20); 

XAML में ...

<Canvas> 
    <TextBox Width="100" Canvas.Left="50" Canvas.Top="20" /> 
</Canvas> 

तुम भी उन्हें सही और नीचे किनारों के सापेक्ष स्थिति कर सकते हैं। शीर्ष और नीचे दोनों को निर्दिष्ट करने से नियंत्रण कैनवास के साथ लंबवत आकार बदल जाएगा। इसी तरह बाएं और दाएं के लिए।

संबंधित मुद्दे