2010-02-09 11 views
6

निम्नलिखित XAML पर विचार करें:WPF ComboBox चयनित आइटम फिर सेट करता है जब मद-स्रोत बदल जाता

<ComboBox Name="CompanyComboBox" 
    HorizontalAlignment="Stretch" 
    ItemsSource="{Binding Path=GlobalData.Companies}" 
    SelectedValuePath="Id" 
    SelectedValue="{Binding Customer.CompanyId, ValidatesOnDataErrors=True}" 
    DisplayMemberPath="Name" /> 

GlobalData.Companies कंपनियों का एक संग्रह (IEnumerable<Company>) है; इस संग्रह को पृष्ठभूमि पर पुनः लोड किया जा सकता है (यह एक webservice से डाउनलोड किया गया है)। जब ऐसा होता है, तो कॉम्बोबॉक्स ठीक से बाध्यकारी के माध्यम से आइटम को पुनः लोड करता है। हालांकि एक साइड इफेक्ट के रूप में, यह भी चयनित आइटम रीसेट करता है!

मैं कॉम्बो बॉक्स सूत्रों का निरीक्षण करने के परावर्तक का इस्तेमाल किया है और जाहिरा तौर पर इस व्यवहार करना है।

वहाँ किसी भी "अच्छा" जिस तरह से यह कैसे चारों ओर पाने के लिए है? मैं जो हासिल करना चाहता हूं, वह यह है कि यदि उपयोगकर्ता "कंपनी ए" का चयन करता है और बाद में कंपनियों की सूची पुनः लोड करता है, तो "कंपनी ए" चयनित रहता है (माना जाता है कि यह नई सूची में है)।

उत्तर

4

हो सकता है कि आप अपने IEnumerable<Company> के बजाय ObservableCollection<Company> उपयोग कर सकते हैं? फिर, पृष्ठभूमि परिवर्तन पर आप केवल नई सूची में नए/अनुपस्थित आइटम को जोड़/निकालेंगे, चयनित आइटम तब तक रहना चाहिए जब तक कि इसे परिवर्तन से हटा दिया न जाए।

आप update your observable collection in a separate thread with a small hack-around कर सकते हैं।

+0

यह समाधान हो सकता है, हालांकि यह उतना अच्छा/आसान नहीं है जितना मैं चाहता हूं: - | –

+0

पृष्ठभूमि थ्रेड से संग्रह को अपडेट करना संभव नहीं है। पृष्ठभूमि में वेब सेवा से वर्तमान संग्रह प्राप्त करें, और उसके बाद (मान लें कि आप पृष्ठभूमिवर्कर का उपयोग कर रहे हैं) RunWorker पूर्ण ईवेंट में 'ObservableCollection ' अपडेट करें। –

0

हम्म, मुझे नहीं पता कि यह एक "अच्छा" तरीका है, लेकिन यदि आप पुनः लोड होने से पहले चयनित आइटम तक पहुंच सकते हैं, तो आप इसे (या इसकी कुंजी या कुछ) सहेज सकते हैं, और इसे प्रोग्रामिक रूप से फिर से चुन सकते हैं रीलोड करने के बाद।

त्वरित mockup:

var selectedItem = myCombo.SelectedItem; 
DoReload(); 
myCombo.SelectedItem = selectedItem; 

लेकिन मुझे लगता है आप के आसपास इस मैनुअल काम से एक और तरीका क्या मतलब है?
आशा इस वैसे भी मदद करता है ...

अद्यतन
ठीक है, मैं एक पृष्ठभूमि धागे से देखते हैं।
आप एक ICollectionView उपयोग कर रहे हैं भी अपने बता गया बाध्य करने के लिए? यदि ऐसा है, तो आप संदर्भ रखने के लिए CurrentItem प्रॉपर्टी का उपयोग कर सकते हैं। मैंने एक त्वरित नकली बना दिया, और यह मेरे सेटअप पर काम कर रहा है।

XAML

<Grid VerticalAlignment="Top"> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition /> 
     <ColumnDefinition /> 
    </Grid.ColumnDefinitions> 
    <ComboBox ItemsSource="{Binding Items}" IsSynchronizedWithCurrentItem="True" Grid.Column="0" Grid.Row="0" DisplayMemberPath="Name"/> 
    <Button Command="{Binding UpdateCommand}" Grid.Column="1" Grid.Row="0">Update</Button> 
</Grid> 

देखें/ViewModel

public partial class Window1 : Window { 
    public Window1() { 
     InitializeComponent(); 
     this.DataContext = new ViewModel(this); 
    } 
} 

public class ViewModel 
{ 
    private readonly Window1 window; 
    private ObservableCollection<Item> items; 
    private ICollectionView view; 

    public ViewModel(Window1 window) { 
     this.window = window; 
     items = new ObservableCollection<Item> 
      { 
       new Item("qwerty"), 
       new Item("hello"), 
       new Item("world"), 
      }; 

     view = CollectionViewSource.GetDefaultView(items); 
    } 

    public ObservableCollection<Item> Items { get { return items; } } 

    public ICommand UpdateCommand { 
     get { return new RelayCommand(DoUpdate); } 
    } 

    public Item SelectedItem { get; set; } 

    private void DoUpdate(object obj) { 
     var act = new Func<List<Item>>(DoUpdateAsync); 
     act.BeginInvoke(CallBack, act); 
    } 

    private List<Item> DoUpdateAsync() { 
     return new List<Item> { 
       new Item("hello"), 
       new Item("world"), 
       new Item("qwerty"), 
      }; 
    } 

    private void CallBack(IAsyncResult result) { 
     try { 
      var act = (Func<List<Item>>)result.AsyncState; 
      var list = act.EndInvoke(result); 

      window.Dispatcher.Invoke(new Action<List<Item>>(delegate(List<Item> lst) { 
                    var current = lst.Single(i => i.Name == ((Item)view.CurrentItem).Name); 
                    Items.Clear(); 
                    lst.ForEach(Items.Add); 
                    view.MoveCurrentTo(current); 
                   }), list); 

     } catch(Exception exc){ Debug.WriteLine(exc); } 
    } 
} 

public class Item { 
    public Item(string name) { 
     Name = name; 
    } 
    public string Name { get; set; } 
} 

आप मामले में कुछ हैंडलिंग करने की आवश्यकता होगी चयनित आइटम नहीं है: यह आप अपने यूआई के लिए एक संदर्भ है मान लिया गया है सूची में लंबा।
IsSynchronizedWithCurrentItem संपत्ति यहाँ महत्वपूर्ण है, वरना यह काम नहीं करेगा!
इसके अलावा, जिस तरह से मुख्य विंडो के संदर्भ में किया जाता है एक डि-ढांचे द्वारा किया जाना चाहिए।

+0

दिक्कत यह है कि DoReload() एक वर्ग जीयूआई के बारे में कोई जानकारी नहीं है कि द्वारा पृष्ठभूमि पर किया जाता है है। जीयूआई बाध्यकारी और INotifyPropertyChanged के माध्यम से नए मूल्यों के बारे में अधिसूचित किया गया है। –

0

Yacoder के रूप में बताया इस वस्तु समानता से कोई लेना देना नहीं है। जब तक आप चयनित इटैम के बजाय चयनित वैल्यू को बाध्य करते हैं, तो आप आइटम्ससोर्स को अनाम प्रकार संग्रह के रूप में परिभाषित कर सकते हैं। तब यह समस्या नहीं होगी (और यदि आपको डेटाबेस से मानों को पढ़ने की आवश्यकता है तो यह भी तेज़ है)।

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