मेरे पास एक ComboBox है जो SelectItem / SelectValue को अपडेट नहीं करता है।
ComboBox ItemSource एक ViewModel क्लास की एक प्रॉपर्टी से जुड़ा है, जो एक संग्रह दृश्य के रूप में RAS फोनबुक प्रविष्टियों के एक समूह को सूचीबद्ध करता है। तब मैं (अलग-अलग समय पर) दोनों SelectedItem
या SelectedValue
ViewModel की अन्य संपत्ति के लिए बाध्य हूं । मैंने डेटाबाइंडिंग द्वारा निर्धारित मानों को डीबग करने के लिए सेव कमांड में एक मैसेजबॉक्स जोड़ा है, लेकिन SelectedItem
/ SelectedValue
बाइंडिंग सेट नहीं किया जा रहा है।
ViewModel वर्ग कुछ इस तरह दिखता है:
public ConnectionViewModel
{
private readonly CollectionView _phonebookEntries;
private string _phonebookeEntry;
public CollectionView PhonebookEntries
{
get { return _phonebookEntries; }
}
public string PhonebookEntry
{
get { return _phonebookEntry; }
set
{
if (_phonebookEntry == value) return;
_phonebookEntry = value;
OnPropertyChanged("PhonebookEntry");
}
}
}
_PhonebookEntries संग्रह एक व्यावसायिक ऑब्जेक्ट से कंस्ट्रक्टर में आरंभीकृत किया जा रहा है। ComboBox XAML कुछ इस तरह दिखता है:
<ComboBox ItemsSource="{Binding Path=PhonebookEntries}"
DisplayMemberPath="Name"
SelectedValuePath="Name"
SelectedValue="{Binding Path=PhonebookEntry}" />
मुझे केवल कॉम्बो बॉक्स में प्रदर्शित वास्तविक स्ट्रिंग मूल्य में दिलचस्पी है, न कि वस्तु के किसी अन्य गुण के रूप में, यह वह मूल्य है जो मुझे आरएएस में पास करने की आवश्यकता है जब मैं वीपीएन कनेक्शन बनाना चाहता हूं, इसलिए DisplayMemberPath
और SelectedValuePath
दोनों के नाम की संपत्ति है ConnectionViewModel। ComboBox एक विंडो पर एक पर DataTemplate
लागू होता है, जिसका ItemsControl
DataContext ViewModel उदाहरण के लिए सेट किया गया है।
ComboBox वस्तुओं की सूची को सही ढंग से प्रदर्शित करता है, और मैं UI में किसी भी समस्या का चयन कर सकता हूं। हालाँकि जब मैं संदेश बॉक्स को कमांड से प्रदर्शित करता हूं, तो PhonebookEntry संपत्ति में अभी भी प्रारंभिक मूल्य है, कॉम्बो बॉक्स से चयनित मूल्य नहीं है। अन्य टेक्स्टबॉक्स इंस्टेंस मैसेजबॉक्स में ठीक और प्रदर्शित कर रहे हैं।
क्या मैं कॉम्बोबॉक्स को डेटाबाइंडिंग के साथ याद कर रहा हूं? मैंने बहुत खोज की है और ऐसा कुछ भी नहीं पा सकता हूँ जो मैं गलत कर रहा हूँ।
यह वह व्यवहार है जिसे मैं देख रहा हूं, हालांकि यह मेरे विशेष संदर्भ में किसी कारण से काम नहीं कर रहा है।
मेरे पास एक MainWindowViewModel है जिसमें CollectionView
ConnectionViewModels है। MainWindowView.xaml फ़ाइल कोड-पीछे में, मैं MainWindowViewModel में DataContext सेट करता हूं। MainWindowView.xaml के पास ItemsControl
ConnectionViewModels के संग्रह के लिए एक बाध्यता है। मेरे पास एक DataTemplate है जो कॉम्बो बॉक्स के साथ-साथ कुछ अन्य टेक्स्टबॉक्स भी रखता है। TextBoxes सीधे ConnectionViewModel के गुणों के लिए बाध्य हैं Text="{Binding Path=ConnectionName}"
।
public class ConnectionViewModel : ViewModelBase
{
public string Name { get; set; }
public string Password { get; set; }
}
public class MainWindowViewModel : ViewModelBase
{
// List<ConnectionViewModel>...
public CollectionView Connections { get; set; }
}
XAML कोड-पीछे:
public partial class Window1
{
public Window1()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
}
फिर XAML:
<DataTemplate x:Key="listTemplate">
<Grid>
<ComboBox ItemsSource="{Binding Path=PhonebookEntries}"
DisplayMemberPath="Name"
SelectedValuePath="Name"
SelectedValue="{Binding Path=PhonebookEntry}" />
<TextBox Text="{Binding Path=Password}" />
</Grid>
</DataTemplate>
<ItemsControl ItemsSource="{Binding Path=Connections}"
ItemTemplate="{StaticResource listTemplate}" />
TextBoxes सभी सही ढंग से बाँधते हैं, और डेटा उनके और ViewModel के बीच कोई परेशानी नहीं है। यह केवल ComboBox है जो काम नहीं कर रहा है।
आप PhonebookEntry वर्ग के संबंध में अपनी धारणा में सही हैं।
मैं जो धारणा बना रहा हूं वह यह है कि मेरे DataTemplate द्वारा उपयोग किए जाने वाले DataContext को स्वचालित रूप से बाइंडिंग पदानुक्रम के माध्यम से सेट किया जाता है, ताकि मुझे इसे प्रत्येक आइटम के लिए स्पष्ट रूप से सेट न करना पड़े ItemsControl
। यह मुझे थोड़ा मूर्खतापूर्ण लगेगा।
यहाँ एक परीक्षण कार्यान्वयन है जो समस्या को प्रदर्शित करता है, ऊपर के उदाहरण के आधार पर।
XAML:
<Window x:Class="WpfApplication7.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<DataTemplate x:Key="itemTemplate">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Path=Name}" Width="50" />
<ComboBox ItemsSource="{Binding Path=PhonebookEntries}"
DisplayMemberPath="Name"
SelectedValuePath="Name"
SelectedValue="{Binding Path=PhonebookEntry}"
Width="200"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ItemsControl ItemsSource="{Binding Path=Connections}"
ItemTemplate="{StaticResource itemTemplate}" />
</Grid>
</Window>
कोड-पीछे :
namespace WpfApplication7
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
}
public class PhoneBookEntry
{
public string Name { get; set; }
public PhoneBookEntry(string name)
{
Name = name;
}
}
public class ConnectionViewModel : INotifyPropertyChanged
{
private string _name;
public ConnectionViewModel(string name)
{
_name = name;
IList<PhoneBookEntry> list = new List<PhoneBookEntry>
{
new PhoneBookEntry("test"),
new PhoneBookEntry("test2")
};
_phonebookEntries = new CollectionView(list);
}
private readonly CollectionView _phonebookEntries;
private string _phonebookEntry;
public CollectionView PhonebookEntries
{
get { return _phonebookEntries; }
}
public string PhonebookEntry
{
get { return _phonebookEntry; }
set
{
if (_phonebookEntry == value) return;
_phonebookEntry = value;
OnPropertyChanged("PhonebookEntry");
}
}
public string Name
{
get { return _name; }
set
{
if (_name == value) return;
_name = value;
OnPropertyChanged("Name");
}
}
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class MainWindowViewModel
{
private readonly CollectionView _connections;
public MainWindowViewModel()
{
IList<ConnectionViewModel> connections = new List<ConnectionViewModel>
{
new ConnectionViewModel("First"),
new ConnectionViewModel("Second"),
new ConnectionViewModel("Third")
};
_connections = new CollectionView(connections);
}
public CollectionView Connections
{
get { return _connections; }
}
}
}
यदि आप उस उदाहरण को चलाते हैं, तो आपको वह व्यवहार मिलेगा जिसकी मैं बात कर रहा हूं। जब आप इसे संपादित करते हैं, तो टेक्स्टबॉक्स इसके बाइंडिंग फाइन को अपडेट करता है, लेकिन कॉम्बो बॉक्स नहीं। बहुत भ्रमित करने वाली बात यह है कि वास्तव में केवल एक चीज जो मैंने की है, वह है माता-पिता ViewModel।
मैं वर्तमान में इस धारणा के तहत श्रम कर रहा हूं कि किसी DataContext के बच्चे के लिए बाध्य वस्तु उस बच्चे को अपने DataContext के रूप में रखती है। मुझे ऐसा कोई भी दस्तावेज़ नहीं मिला है जो इसे एक या दूसरे तरीके से साफ़ करता हो।
अर्थात,
विंडो ->
डेटा कॉन्टेक्स्ट = मेनविंडो व्यूमॉडल ..इतिमाएँ -> डेटाऑन्टेक्स्ट.फोनबुकइनट्रीज के लिए बाध्य
....
मुझे नहीं पता कि क्या मेरी धारणा को कोई बेहतर (?) बताता है।
मेरी धारणा की पुष्टि करने के लिए, टेक्स्टबॉक्स के बाइंडिंग को बदल दें
<TextBox Text="{Binding Mode=OneWay}" Width="50" />
और यह TextBox बाइंडिंग रूट दिखाएगा (जो मैं DataContext से तुलना कर रहा हूं) ConnectionViewModel उदाहरण है।
<
T के रूप>
में और संपत्ति गेट्टर में _list.AsReadOnly () के समान गुणों का खुलासा कर रहा हूं , जिस तरह से आपने उल्लेख किया है। यह काम कर रहा है क्योंकि मुझे उम्मीद है कि मूल विधि होगी। इसके अलावा, इसने मेरे दिमाग को पार कर दिया कि जब आइटम्स सोर्स बाध्यकारी ठीक काम कर रहा था, तो मैं कॉम्बोबॉक्स में चयनित आइटम तक पहुंचने के लिए ViewModel में वर्तमान संपत्ति का उपयोग कर सकता था। फिर भी, यह ComboBoxes SelectValue / SelectItem संपत्ति को बाइंड करने के रूप में स्वाभाविक रूप से महसूस नहीं करता है।