2014-09-04 12 views
9

में उपयोगकर्ता नियंत्रण की निर्भरता संपत्ति को सही ढंग से कैसे बाध्य करें, मैं सही ढंग से को WPF के साथ उपयोगकर्ता नियंत्रण को कार्यान्वित करने के लिए एक स्वच्छ, सरल, उदाहरण खोजने में असमर्थ रहा हूं जिसमें एमवीवीएम ढांचे के भीतर एक निर्भरता संपत्ति है । जब भी मैं usercontrol को datacontext असाइन करता हूं, तो मेरा कोड नीचे विफल रहता है।एमवीवीएम फ्रेमवर्क

मैं कोशिश कर रहा हूँ:

  1. बुला ItemsControl पर निर्भरता को संपत्ति सेट करें, और
  2. कि निर्भरता संपत्ति कहा जाता usercontrol की ViewModel करने के लिए उपलब्ध का मूल्य सुनिश्चित करें।

मुझे अभी भी बहुत कुछ सीखना है और ईमानदारी से किसी भी मदद की सराहना करते हैं।

यह शीर्षतम उपयोगकर्ता नियंत्रण में आइटम नियंत्रण है जो निर्भरता गुण TextInControl (किसी अन्य प्रश्न से उदाहरण) के साथ InkStringView उपयोगकर्ता नियंत्रण पर कॉल कर रहा है।

<ItemsControl 
       ItemsSource="{Binding Strings}" x:Name="self" > 

     <ItemsControl.ItemsPanel> 
      <ItemsPanelTemplate> 
       <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Orientation="Vertical" /> 
      </ItemsPanelTemplate> 
     </ItemsControl.ItemsPanel> 


     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <DataTemplate.Resources> 
        <Style TargetType="v:InkStringView"> 
         <Setter Property="FontSize" Value="25"/> 
         <Setter Property="HorizontalAlignment" Value="Left"/> 
        </Style> 
       </DataTemplate.Resources> 

       <v:InkStringView TextInControl="{Binding text, ElementName=self}" /> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 

निर्भरता संपत्ति के साथ InkStringView उपयोगकर्ता नियंत्रण यहां है।

XAML: 
<UserControl x:Class="Nova5.UI.Views.Ink.InkStringView" 
     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" 
     x:Name="mainInkStringView" 
     mc:Ignorable="d" 
     d:DesignHeight="300" d:DesignWidth="300"> 
<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition/> 
     <RowDefinition/> 
    </Grid.RowDefinitions> 

    <TextBlock Grid.Row="0" Text="{Binding TextInControl, ElementName=mainInkStringView}" /> 
    <TextBlock Grid.Row="1" Text="I am row 1" /> 
</Grid> 

Code-Behind file: 
namespace Nova5.UI.Views.Ink 
{ 
public partial class InkStringView : UserControl 
{ 
    public InkStringView() 
    { 
     InitializeComponent(); 
     this.DataContext = new InkStringViewModel(); <--THIS PREVENTS CORRECT BINDING, WHAT 
    }             --ELSE TO DO????? 

    public String TextInControl 
    { 
     get { return (String)GetValue(TextInControlProperty); } 
     set { SetValue(TextInControlProperty, value); } 
    } 

    public static readonly DependencyProperty TextInControlProperty = 
     DependencyProperty.Register("TextInControl", typeof(String), typeof(InkStringView)); 

} 

}

+0

आइटम नियंत्रण (या किसी भी व्युत्पन्न वर्ग) के आइटम टेम्पलेट में नियंत्रणों का डेटा कॉन्टेक्स्ट स्वचालित रूप से स्रोत संग्रह में संबंधित आइटम पर WPF द्वारा असाइन किया जाता है। आपके मामले में यह 'स्ट्रिंग' संग्रह से एक तत्व होगा। यदि 'स्ट्रिंग्स' ऑब्जेक्ट्स का एक संग्रह है जिसमें 'टेक्स्ट' प्रॉपर्टी है, तो आप डेटा टेम्पलेट में' TextInControl = "{बाइंडिंग टेक्स्ट} 'के रूप में बाध्यकारी लिखेंगे और * स्पष्ट रूप से * किसी भी अन्य डेटा कॉन्टेक्स्ट को सेट नहीं करेंगे। मैं इस विषय पर पढ़ने का सुझाव दूंगा। – Clemens

+0

देखें [डेटा बाध्यकारी अवलोकन] (http://msdn.microsoft.com/en-us/library/ms752347.aspx) और [डेटा टेम्पलेटिंग अवलोकन] (http://msdn.microsoft.com/en-us/library /ms742521.aspx)। – Clemens

+0

@ क्लेमेंस हाय। ElementName = को छोड़कर ... कॉलिंग आइटम कंट्रोल से अभी भी "मैं पंक्ति 1" प्रदर्शित होने के साथ समाप्त होता हूं और एक रिक्त रेखा जहां पंक्ति 0 पर टेक्स्टब्लॉक होना चाहिए। ??? विचार? –

उत्तर

12

कई कारणों से आप DataContext सीधे सेट कभी नहीं करना चाहिए में से एक है कि UserControl से ही।

आप हां, तो आप आगे किसी भी अन्य DataContext इसके साथ उपयोग कर सकते हैं करते हैं क्योंकि UserControl के DataContext एक उदाहरण है कि केवल UserControl पराजय किस तरह अलग यूआई होने के WPF के सबसे बड़े फायदों में से एक और करने के लिए उपयोग किया है करने के लिए hardcoded है डेटा परतें।

वहाँ WPF

  1. एक स्वसंपूर्ण UserControl कि एक विशिष्ट DataContext बिना कहीं भी इस्तेमाल किया जा सकता आवश्यक किया जा रहा में UserControls का उपयोग कर के दो मुख्य तरीके हैं। इस तरह के एक कैलेंडर नियंत्रण या पॉपअप नियंत्रण के रूप में

    <v:InkStringView TextInControl="{Binding SomeValue}" /> 
    

    विशिष्ट उदाहरण मैं के बारे में सोच सकते हैं कुछ भी सामान्य होगा:

    UserControl के इस प्रकार के आम तौर पर किसी भी मान यह जरूरत के लिए DependencyProperties को उजागर करता है, और इस तरह इस्तेमाल किया जाएगा।

  2. UserControl जिसका उपयोग केवल विशिष्ट Model या ViewModel के साथ किया जाना है।

    ये UserControls कहीं अधिक मेरे लिए आम हैं, और आप अपने मामले में के लिए शायद क्या देख रहे है। कैसे मैं इस तरह के एक UserControl का प्रयोग करेंगे का एक उदाहरण इस होगा:

    <v:InkStringView DataContext="{Binding MyInkStringViewModelProperty}" /> 
    

    या अधिक बार, यह एक अंतर्निहित DataTemplate साथ इस्तेमाल किया जाएगा। एक अंतर्निहित DataTemplate एक DataType और कोई Key के साथ एक DataTemplate है, और WPF स्वचालित रूप से इस कभी भी टेम्पलेट यह निर्दिष्ट प्रकार का ऑब्जेक्ट प्रस्तुत करना चाहता है का उपयोग करेगा। जब इस पद्धति का उपयोग

    <Window.Resources> 
        <DataTemplate DataType="{x:Type m:InkStringViewModel}"> 
         <v:InkStringView /> 
        </DataTemplate> 
    <Window.Resources> 
    
    <!-- Binding to a single ViewModel --> 
    <ContentPresenter Content="{Binding MyInkStringViewModelProperty}" /> 
    
    <!-- Binding to a collection of ViewModels --> 
    <ItemsControl ItemsSource="{Binding MyCollectionOfInkStringViewModels}" /> 
    

    नहीं ContentPresenter.ItemTemplate या ItemsControl.ItemTemplate की जरूरत है।

इन दोनों तरीकों मिश्रण अप मत करो, यह अच्छी तरह से जाना नहीं है :)


लेकिन वैसे भी, एक ही देर में अपने विशिष्ट समस्या को समझाने के लिए और अधिक विस्तार

जब आप इस

<v:InkStringView TextInControl="{Binding text}" /> 

आप मूल रूप से

कह रहे हैं की तरह अपने UserControl बनाने
var vw = new InkStringView() 
vw.TextInControl = vw.DataContext.text; 

vw.DataContext XAML में कहीं भी निर्दिष्ट नहीं है, तो यह मूल आइटम है, जो

vw.DataContext = Strings[x]; 

में जो परिणाम से विरासत में मिला हो जाता है तो अपने बंधन है कि सेट TextInControl = vw.DataContext.text वैध है और रनटाइम पर ठीक हल करता है।

लेकिन जब आप अपने UserControl निर्माता

this.DataContext = new InkStringViewModel(); 

DataContext में इस चलाने के एक मान पर सेट है, तो अब अपने माता-पिता से विरासत में मिला हो जाता है।

तो अब है कि इस तरह दिखता है चलाने हो जाता है कोड:

var vw = new InkStringView() 
vw.DataContext = new InkStringViewModel(); 
vw.TextInControl = vw.DataContext.text; 

और स्वाभाविक रूप से, InkStringViewModel तो बाध्यकारी कार्यावधि में विफल रहता है, एक संपत्ति text कहा जाता है नहीं है।

+0

ऊपर बताए गए दो तरीकों पर सीखने के लिए कोई अच्छा संसाधन है? –

+0

@ एहसान सजदद मैं अभी किसी भी बारे में नहीं सोच सकता, लेकिन एक बार जब आप महसूस करते हैं कि यह कैसे काम करता है, तो वे याद रखने के लिए बहुत आसान अवधारणाएं हैं। या तो ** ए) ** अपने उपयोगकर्ता नियंत्रण XAML को इस तरह से लिखें कि यह 'डेटाकॉन्टेक्स्ट' (आमतौर पर निर्भरता प्रॉपर्टीज का उपयोग करके किया जाता है, जैसे ओपी है), या ** बी) उपयोगकर्ता नियंत्रण XAML धारणा के साथ कि 'DataContext' एक विशिष्ट डेटा प्रकार (आमतौर पर एक मॉडल या व्यूमोडेल) है। और किसी भी समय आपने कभी भी UserControl के भीतर से 'DataContext' प्रॉपर्टी सेट नहीं करनी चाहिए :) – Rachel

+0

@ राहेल तो ... यदि 2 में, UserControl का व्यूमोडल वास्तव में कॉलिंग मॉड्यूल का व्यूमोडेल है ?? मैं ContentPresenter से परिचित नहीं हूं ... यह कहां फिट है? –

1

आप बहुत करीब हैं। समस्या यह है कि आप अपने UserControl के लिए ViewModel बना रहे हैं। यह एक गंध है।

उपयोगकर्ता नियंत्रण किसी भी अन्य नियंत्रण की तरह दिखना चाहिए और व्यवहार करना चाहिए, जैसा कि बाहर से देखा गया है। आप नियंत्रण पर सही ढंग से उजागर गुण हैं, और इन गुणों के लिए आंतरिक नियंत्रण बाध्यकारी हैं। यह सब सही है।

जहां आप असफल हो जाते हैं, सब कुछ के लिए व्यूमोडेल बनाने की कोशिश कर रहा है। तो बेवकूफ InkStringViewModel खाओ और जो भी अपने दृश्य मॉडल को बांधने के लिए नियंत्रण का उपयोग कर रहे हैं।

यदि आप "मॉडल मॉडल में तर्क के बारे में क्या पूछते हैं" पूछने के लिए प्रलोभित हैं? अगर मैं इससे छुटकारा पाता हूं तो मुझे कोडबेंड में कोड रखना होगा! " मैं जवाब देता हूं, "क्या यह व्यवसाय तर्क है? इसे किसी भी तरह से अपने उपयोगकर्ता नियंत्रण में एम्बेड नहीं किया जाना चाहिए। और एमवीवीएम! = कोई कोडबेइंड नहीं। अपने यूआई तर्क के लिए कोडबेइंड का उपयोग करें। यह वह जगह है जहां यह संबंधित है।"

+0

तार्किक रूप से प्रत्येक घटक में एक मॉडल होता है, कभी-कभी इसे एन गुणों (फर्स्टनाम, लास्टनाम, पता ...) में विभाजित किया जाता है, कभी-कभी आपके पास एक समग्र वस्तु (व्यक्ति) होती है, कभी-कभी विषम डेटा वाला एक संपूर्ण मॉडल होता है। – Pragmateek

+1

@ प्रागमैटेक और कभी-कभी गाय चंद्रमा पर कूदता है, लेकिन उस प्रश्न या इस उत्तर के साथ भी कोई डर नहीं है। – Will

+0

मैं इस टिप्पणी को जोड़ रहा था क्योंकि यह आपके उत्तर की पहली टिप्पणी है ("यह एक गंध है") जो हमेशा सत्य नहीं है, बस इसे स्पष्ट करना चाहता था। और कृपया संयोग से मूर्ख मत बनो, मैं डाउनवॉटर नहीं हूं (मैं कभी भी डाउनवोट नहीं करता क्योंकि मेरी प्रोफ़ाइल आपको दिखाएगी और विशेष रूप से आपके पास उतनी ही प्रतिष्ठा नहीं होगी) :) – Pragmateek

2

आपको यहां 2 चीजें करने की ज़रूरत है (मुझे लगता है कि स्ट्रिंग्स ObservableCollection<string> है)।

1) InkStringView कन्स्ट्रक्टर से this.DataContext = new InkStringViewModel(); हटाएं। डेटाकॉन्टेक्स्ट स्ट्रिंग्स ऑब्जेर्जेबल कोलेक्शन का एक तत्व होगा।

2) बदलें

<v:InkStringView TextInControl="{Binding text, ElementName=self}" /> 

<v:InkStringView TextInControl="{Binding }" /> 

को XAML आप ItemsControl पर एक "पाठ" संपत्ति के मूल्य TextInControl करने के लिए बाध्य करने के लिए की तलाश में है। TextInControl को बाध्य करने के लिए मैंने डेटाकॉन्टेक्स्ट (जो एक स्ट्रिंग होता है) का उपयोग करके xaml डाल दिया। यदि स्ट्रिंग्स वास्तव में एक स्ट्रिंग के साथ एक अवलोकन करने योग्य चयन है जो कुछ प्रॉपर्टी की संपत्ति है जिसे आप बांधना चाहते हैं तो उसे इसके बजाय बदल दें।

<v:InkStringView TextInControl="{Binding SomeProperty}" /> 
+0

धारणा गलत है। 'स्ट्रिंग्स' प्रकार स्ट्रिंग की सार्वजनिक 'टेक्स्ट' प्रॉपर्टी के साथ ऑब्जेक्ट्स का संग्रह है। – Clemens

+0

हाँ ... तो नीचे विकल्प –

+0

का उपयोग करें मैंने इसे अपने कोड का उपयोग करके दोनों तरीकों का परीक्षण किया और यह आपकी टिप्पणियों में जैसा कि आपने माना है इसे ठीक करता है। हालांकि TextInControl के लिए बाध्यकारी ठीक है। –

3

ऐसा लगता है कि आप यूसी के मॉडल के साथ मूल दृश्य के मॉडल को मिश्रित कर रहे हैं।

MainViewModel:

using System.Collections.Generic; 

namespace UCItemsControl 
{ 
    public class MyString 
    { 
     public string text { get; set; } 
    } 

    public class MainViewModel 
    { 
     public ObservableCollection<MyString> Strings { get; set; } 

     public MainViewModel() 
     { 
      Strings = new ObservableCollection<MyString> 
      { 
       new MyString{ text = "First" }, 
       new MyString{ text = "Second" }, 
       new MyString{ text = "Third" } 
      }; 
     } 
    } 
} 

MainWindow यह का उपयोग करता है:

<Window x:Class="UCItemsControl.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:v="clr-namespace:UCItemsControl" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.DataContext> 
     <v:MainViewModel></v:MainViewModel> 
    </Window.DataContext> 
    <Grid> 
     <ItemsControl 
       ItemsSource="{Binding Strings}" x:Name="self" > 

      <ItemsControl.ItemsPanel> 
       <ItemsPanelTemplate> 
        <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Orientation="Vertical" /> 
       </ItemsPanelTemplate> 
      </ItemsControl.ItemsPanel> 


      <ItemsControl.ItemTemplate> 
       <DataTemplate> 
        <DataTemplate.Resources> 
         <Style TargetType="v:InkStringView"> 
          <Setter Property="FontSize" Value="25"/> 
          <Setter Property="HorizontalAlignment" Value="Left"/> 
         </Style> 
        </DataTemplate.Resources> 

        <v:InkStringView TextInControl="{Binding text}" /> 
       </DataTemplate> 
      </ItemsControl.ItemTemplate> 
     </ItemsControl> 
    </Grid> 
</Window> 

आपका यूसी (DataContext का कोई सेट):

यहां एक नमूना है कि अपने कोड से मेल खाता है

public partial class InkStringView : UserControl 
{ 
    public InkStringView() 
    { 
     InitializeComponent(); 
    } 

    public String TextInControl 
    { 
     get { return (String)GetValue(TextInControlProperty); } 
     set { SetValue(TextInControlProperty, value); } 
    } 

    public static readonly DependencyProperty TextInControlProperty = 
     DependencyProperty.Register("TextInControl", typeof(String), typeof(InkStringView)); 
} 

(आपका XAML ठीक है)

इसी के साथ मैं प्राप्त कर सकते हैं क्या मुझे लगता है कि उम्मीद परिणाम, मूल्यों की एक सूची है:

First 
I am row 1 
Second 
I am row 1 
Third 
I am row 1