2010-11-12 11 views
39

[संपादित करें] में बाध्यकारी के लिए आंतरिक नियंत्रण गुणों का खुलासा करना [संपादित करें]: मुझे पता चला कि यह स्वयं कैसे करें। मैंने उम्मीद में अपना समाधान पोस्ट किया कि यह किसी और को गुगलिंग के कुछ दिन बचाएगा। यदि आप एक डब्ल्यूपीएफ गुरु हैं, तो कृपया मेरा समाधान देखें और मुझे यह बताने दें कि ऐसा करने के लिए एक बेहतर/अधिक सुरुचिपूर्ण/अधिक कुशल तरीका है या नहीं। विशेष रूप से, मुझे यह जानने में दिलचस्पी है कि मुझे क्या पता नहीं है ... यह समाधान मुझे सड़क पर कैसे फेंकने वाला है? समस्या वास्तव में आंतरिक नियंत्रण गुणों को उजागर करने के लिए उबालती है।डब्ल्यूपीएफ

समस्या: मैं एक XML फ़ाइल के लिए WPF में डेटा-बाउंड जीयूआई स्वत: उत्पन्न करने के लिए कुछ कोड बना रहा हूं। मेरे पास एक xsd फ़ाइल है जो मुझे नोड प्रकारों आदि को निर्धारित करने में मदद कर सकती है। सरल कुंजी/मान तत्व आसान हैं।

जब मैं इस तत्व पार्स:

<Key>value</Key> 

मैं एक नया 'KeyValueControl' बना सकते हैं और इस तत्व को DataContext सेट कर सकते हैं। KeyValue को UserControl के रूप में परिभाषित किया गया है और इसमें कुछ सरल बाइंडिंग हैं। यह किसी भी साधारण XElement के लिए बहुत अच्छा काम करता है।

XAML इस पर नियंत्रण के अंदर इस तरह दिखता है:

<Label Content={Binding Path=Name} /> 
<TextBox Text={Binding Path=Value} /> 

परिणाम एक लाइन तत्व का नाम और मान है कि मैं संपादित कर सकते हैं के साथ एक पाठ बॉक्स के साथ एक लेबल किया है।

अब, ऐसे समय हैं जहां मुझे वास्तविक मूल्य के बजाय लुकअप मान प्रदर्शित करने की आवश्यकता है। मैं उपरोक्त KeyValueControl के समान 'KeyValueComboBox' बनाना चाहता हूं लेकिन आइटम्ससोर्स, डिस्प्ले और वैल्यू पथ निर्दिष्ट करने में सक्षम हूं (फ़ाइल में जानकारी के आधार पर)। 'नाम' और 'मान' बाइंडिंग KeyValueControl के समान होंगी।

मुझे नहीं पता कि एक मानक उपयोगकर्ता नियंत्रण इसे कैसे संभाल सकता है, या अगर मुझे चयनकर्ता से उत्तराधिकारी होना है।

नियंत्रण कुछ इस तरह दिखेगा में XAML:

<Label Content={Binding Path=Name} /> 
<ComboBox SelectedValue={Binding Path=Value} 
      ItemsSource={Binding [BOUND TO THE ItemsSource PROPERTY OF THIS CUSTOM CONTROL] 
      DisplayMemberPath={Binding [BOUND TO THE DisplayMemberPath OF THIS CUSTOM CONTROL] 
      SelectedValuePath={Binding [BOUND TO THE SelectedValuePath OF THIS CUSTOM CONTROL]/> 

मेरी कोड, मैं तो कुछ इस तरह करना होगा में (यह सोचते हैं कि इस नोड एक 'बात' है और की एक सूची प्रदर्शित करने की जरूरत है उपयोगकर्ता तो हालात आईडी चुन सकते हैं:

var myBoundComboBox = new KeyValueComboBox(); 
myBoundComboBox.ItemsSource = getThingsList(); 
myBoundComboBox.DisplayMemberPath = "ThingName"; 
myBoundComboBox.ValueMemberPath = "ThingID" 
myBoundComboBox.DataContext = thisXElement; 
... 
myStackPanel.Children.Add(myBoundComboBox) 

तो मेरी प्रश्न हैं:

1) मैं नियंत्रण या चयनकर्ता से मेरी KeyValueComboBox वारिस चाहिए?

2) अगर मुझे नियंत्रण से उत्तराधिकारी होना चाहिए, तो मैं बाध्यकारी के लिए आंतरिक कॉम्बो बॉक्स के आइटमसोर्स, डिस्प्लेमेम्बरपाथ और वैल्यूमम्बरपैथ का खुलासा कैसे करूं?

3) अगर मुझे चयनकर्ता से उत्तराधिकारी की आवश्यकता है, तो क्या कोई इसका एक छोटा सा उदाहरण प्रदान कर सकता है कि मैं इसके साथ कैसे शुरुआत कर सकता हूं? दोबारा, मैं डब्ल्यूपीएफ के लिए नया हूं इसलिए एक अच्छा, सरल उदाहरण वास्तव में मदद करेगा अगर वह सड़क है जिसे मुझे लेने की ज़रूरत है।

उत्तर

47

मैं यह समझने लगा कि यह कैसे स्वयं किया जाए। मैं यहां जवाब पोस्ट कर रहा हूं ताकि अन्य लोग एक समाधान देख सकें जो काम करता है, और शायद एक डब्ल्यूपीएफ गुरु आ जाएगा और मुझे ऐसा करने के लिए एक बेहतर/अधिक सुरुचिपूर्ण तरीका दिखाएगा।

तो, उत्तर # 2 हो गया। आंतरिक गुणों का खुलासा सही जवाब साबित होता है। इसे स्थापित करना वास्तव में बहुत आसान है .. एक बार जब आप जानते हैं कि यह कैसे करें।इस के कई पूर्ण उदाहरण नहीं हैं (जो मुझे मिल सकता है), इसलिए उम्मीद है कि यह किसी और की मदद करेगा जो इस समस्या में चलता है।

ComboBoxWithLabel.xaml.cs

इस फाइल में महत्वपूर्ण बात यह है DependencyProperties का उपयोग है। ध्यान दें कि हम अभी जो कर रहे हैं वह सिर्फ गुणों (लेबलकंटेंट और आइटमसोर्स) को उजागर कर रहा है। एक्सएएमएल इन बाहरी गुणों के लिए आंतरिक नियंत्रण के गुणों को तारों का तार रखेगा।

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 System.Collections; 

namespace BoundComboBoxExample 
{ 
    /// <summary> 
    /// Interaction logic for ComboBoxWithLabel.xaml 
    /// </summary> 
    public partial class ComboBoxWithLabel : UserControl 
    { 
     // Declare ItemsSource and Register as an Owner of ComboBox.ItemsSource 
     // the ComboBoxWithLabel.xaml will bind the ComboBox.ItemsSource to this 
     // property 
     public IEnumerable ItemsSource 
     { 
      get { return (IEnumerable)GetValue(ItemsSourceProperty); } 
      set { SetValue(ItemsSourceProperty, value); } 
     } 

     public static readonly DependencyProperty ItemsSourceProperty = 
      ComboBox.ItemsSourceProperty.AddOwner(typeof(ComboBoxWithLabel)); 

     // Declare a new LabelContent property that can be bound as well 
     // The ComboBoxWithLable.xaml will bind the Label's content to this 
     public string LabelContent 
     { 
      get { return (string)GetValue(LabelContentProperty); } 
      set { SetValue(LabelContentProperty, value); } 
     } 

     public static readonly DependencyProperty LabelContentProperty = 
      DependencyProperty.Register("LabelContent", typeof(string), typeof(ComboBoxWithLabel)); 

     public ComboBoxWithLabel() 
     { 
      InitializeComponent(); 
     } 
    } 
} 

ComboBoxWithLabel.xaml

Xaml लेबल और ComboBox ItemsSource पर बाइंडिंग के अपवाद के साथ बिल्कुल स्पष्ट है,। मैंने पाया कि इन बाइंडिंग को सही करने का सबसे आसान तरीका है .cs फ़ाइल (उपरोक्त के रूप में) में गुणों को घोषित करना और फिर गुण फलक से बाइंडिंग स्रोत सेट करने के लिए VS2010 डिज़ाइनर का उपयोग करना। अनिवार्य रूप से, यह एकमात्र तरीका है जिसे मैं आधार नियंत्रण में आंतरिक नियंत्रण गुणों को बांधने के बारे में जानता हूं। यदि ऐसा करने का एक बेहतर तरीका है, तो कृपया मुझे बताएं।

<UserControl x:Class="BoundComboBoxExample.ComboBoxWithLabel" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      mc:Ignorable="d" 
      d:DesignHeight="28" d:DesignWidth="453" xmlns:my="clr-namespace:BoundComboBoxExample"> 
    <Grid> 
     <DockPanel LastChildFill="True"> 
      <!-- This will bind the Content property on the label to the 'LabelContent' 
       property on this control--> 
      <Label Content="{Binding Path=LabelContent, 
          RelativeSource={RelativeSource FindAncestor, 
              AncestorType=my:ComboBoxWithLabel, 
              AncestorLevel=1}}" 
        Width="100" 
        HorizontalAlignment="Left"/> 
      <!-- This will bind the ItemsSource of the ComboBox to this 
       control's ItemsSource property --> 
      <ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, 
            AncestorType=my:ComboBoxWithLabel, 
            AncestorLevel=1}, 
            Path=ItemsSource}"></ComboBox> 
      <!-- you can do the same thing with SelectedValuePath, 
       DisplayMemberPath, etc, but this illustrates the technique --> 
     </DockPanel> 

    </Grid> 
</UserControl> 

MainWindow.xaml

XAML इस सब पर दिलचस्प नहीं है का उपयोग करने के .. जो है मैं वास्तव में क्या करना चाहता था। आप सभी मानक WPF तकनीकों के माध्यम से आइटमसोर्स और लेबलकंटेंट सेट कर सकते हैं।

<Window x:Class="BoundComboBoxExample.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="86" Width="464" xmlns:my="clr-namespace:BoundComboBoxExample" 
     Loaded="Window_Loaded"> 
    <Window.Resources> 
     <ObjectDataProvider x:Key="LookupValues" /> 
    </Window.Resources> 
    <Grid> 
     <my:ComboBoxWithLabel LabelContent="Foo" 
           ItemsSource="{Binding Source={StaticResource LookupValues}}" 
           HorizontalAlignment="Left" 
           Margin="12,12,0,0" 
           x:Name="comboBoxWithLabel1" 
           VerticalAlignment="Top" 
           Height="23" 
           Width="418" /> 
    </Grid> 
</Window> 

पूर्णता के लिए, यहाँ MainWindow.xaml.cs

/// <summary> 
/// Interaction logic for MainWindow.xaml 
/// </summary> 
public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    private void Window_Loaded(object sender, RoutedEventArgs e) 
    { 
     ((ObjectDataProvider)FindResource("LookupValues")).ObjectInstance = 
      (from i in Enumerable.Range(0, 5) 
      select string.Format("Bar {0}", i)).ToArray(); 

    } 
} 
+0

मैं एक ऐसी ही तकनीक का उपयोग कर रहा हूँ, लेकिन मुसीबत जब में चल मेरी खुद को संबंधित रिश्तेदार स्रोत बाइंडिंग का उपयोग करने के लिए सेट अप किया जाता है। तो आपके मामले में यदि आपने कॉम्बोबॉक्स इटैम तत्वों को अपने आइटमसोर्स के रूप में संग्रहित किया है और किसी को ढूँढने वाले रिश्तेदार स्रोत का उपयोग करके लॉजिकल पेड़ को बाध्यकारी है, तो पता लगाने के लिए उस उत्तरदाता तत्व पर परिभाषित संपत्ति से जुड़ें, फिर बाध्यकारी विफल हो जाएगी। – jpierson

+0

मैंने इसे एक बहुत ही समान मामले, अच्छे उत्तर के लिए उपयोग किया। मेरे आवेदन में मैं एक Combobox के चयनित इटैम के लिए बाध्यकारी था। यह केवल ध्यान दिया जाना चाहिए कि बाध्यकारी ठीक से काम करने के लिए, कुछ मामलों में बाध्यकारी मोड = twoway और UpdateSourceTrigger = PropertyChanged में जोड़ना आवश्यक है – Cocomico

0

मैं अपने समाधान करने की कोशिश की है, लेकिन यह मेरे लिए विफल रहता है। यह मान को आंतरिक नियंत्रण में भी पारित नहीं करता है।

XAML में से
// Declare IsReadOnly property and Register as an Owner of TimePicker (base InputBase).IsReadOnly the TimePickerEx.xaml will bind the TimePicker.IsReadOnly to this property 
    // does not work: public static readonly DependencyProperty IsReadOnlyProperty = InputBase.IsReadOnlyProperty.AddOwner(typeof(TimePickerEx)); 

    public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register("IsReadOnly", typeof (bool), typeof (TimePickerEx), new PropertyMetadata(default(bool))); 
    public bool IsReadOnly 
    { 
     get { return (bool) GetValue(IsReadOnlyProperty); } 
     set { SetValue(IsReadOnlyProperty, value); } 
    } 

: उस तरह बाहरी के भीतरी बाहरी नियंत्रण और बाध्य में एक ही निर्भरता संपत्तियों की घोषणा क्या मैंने किया है

<UserControl x:Class="CBRControls.TimePickerEx" x:Name="TimePickerExControl" 
     ... 
     > 

     <xctk:TimePicker x:Name="Picker" 
       IsReadOnly="{Binding ElementName=TimePickerExControl, Path=IsReadOnly}" 
       ... 
     /> 

    </UserControl>