2014-03-06 63 views
3

我使用ComboBox綁定到視圖模型的字符串屬性。我選擇ComboBox而不是TextBox,因爲我想要從列表中選擇一個選項(作爲建議),但如果ItemsSource更改,我不想更改所選文本。如何使用ComboBox的Text屬性禁用ItemsSource同步

我試圖設置IsSynchronizedWithCurrentItem屬性爲false,但是當建議列表更改(在選定文本的位置)時,文本更改爲空。 似乎ComboBox已經記住輸入的文本也在列表中,當這個項目消失時,Text屬性也被清除。

所以我的問題是:這是一個錯誤,或者我做錯了什麼? 如果這是一個錯誤,你能提出一些解決辦法嗎?

我創建了preproduces這個示例項目:

在XAML

<Window x:Class="TestProject1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <ComboBox IsSynchronizedWithCurrentItem="False" ItemsSource="{Binding Items}" 
        IsEditable="True" Text="{Binding SelectedText, UpdateSourceTrigger=PropertyChanged}" 
        HorizontalAlignment="Left" Margin="10,39,0,0" VerticalAlignment="Top" Width="120"/> 
     <Button Click="Button_Click" Content="Update list" 
       HorizontalAlignment="Left" Margin="10,82,0,0" VerticalAlignment="Top" Width="75"/> 
    </Grid> 
</Window> 

在後面的代碼:

public partial class MainWindow : Window, INotifyPropertyChanged 
    { 
     public MainWindow() { 
      InitializeComponent(); 

      this.DataContext = this; 
      Items = new List<string>() { "0", "1", "2" }; 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 
     private void RaisePropertyChanged(string propertyName) { 
      if (PropertyChanged != null) { 
       PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
      } 
     } 

     private List<string> _items; 
     public List<string> Items {// I use IEnumerable<string> with LINQ, but the effect is the same 
      get { return _items; } 
      set { 
       if (_items != value) { 
        _items = value; 
        RaisePropertyChanged("Items"); 
       } 
      } 
     } 

     private string _selectedText; 
     public string SelectedText { 
      get { return _selectedText; } 
      set { 
       if (_selectedText != value) { 
        _selectedText = value; 
        RaisePropertyChanged("SelectedText"); 
       } 
      } 
     } 

     private void Button_Click(object sender, RoutedEventArgs e) { 
      var changed = Items.ToList();//clone 
      int index = changed.IndexOf(SelectedText); 
      if (index >= 0) { 
       changed[index] += "a";//just change the currently selected value 
      } 
      Items = changed;//update with new list 
     } 

    } 

回答

0

後您的ItemsSource已經改變,提升的屬性變更了選定的文本刷新UI。

在您的作品集二傳手

所以,進行更改:

RaisePropertyChanged("Items"); 
RaisePropertyChanged("SelectedText"); 

編輯:在您的例子中,你不只是改變的ItemSource,你改變了這一切是當前選定一個項目的文本但在舊文本上具有文本綁定。你期望看到/發生什麼?您是否希望所選的商品保持不變,即使其文字更改?

+0

我試了一下,並沒有奏效。我不知道它爲什麼要工作? – user3387366

+0

它應該工作,因爲當ItemsSource更改SelectedItem將被清除的概念時 - 通過RaisingPropertyChanged選定的項目,您可以重新選擇哪個項目。但我剛剛注意到你正試圖改變所選項目的*文本*,並以某種方式保留依賴於文本的綁定......這將無法工作。我會編輯我的答案。 – Mashton

+0

首先,我想從列表中選擇文字。然後,我不希望在更改項目源後更改所選文本。如果集合(字符串)的類型是引用類型,那麼這是一個預期的行爲。但是字符串是一個值類型,因此在選擇它之後應該保持它被選中的狀態(新副本)。 – user3387366

0

這是我對這個問題的解決辦法:

public class ComboBox : System.Windows.Controls.ComboBox 
{ 
    private bool ignore = false; 
    protected override void OnSelectionChanged(SelectionChangedEventArgs e) 
    { 
     if (!ignore) 
     { 
      base.OnSelectionChanged(e); 
     } 
    } 

    protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) 
    { 
     ignore = true; 
     try 
     { 
      base.OnItemsChanged(e); 
     } 
     finally 
     { 
      ignore = false; 
     } 
    } 
} 
0

修改Button_Click像這樣(註釋行是新的):

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    string tempCopy = SelectedText; // Create a copy of the current value 

    var changed = Items.ToList(); 
    int index = changed.IndexOf(SelectedText); 
    if (index >= 0) 
    { 
     changed[index] += "a"; 
    } 
    Items = changed; 

    SelectedText = tempCopy; // Replace the selected text with the copy we made 
} 

這樣做只是使得SelectedText副本前Items變化,然後在更改完成後替換它。

  1. 複製SelectedText
  2. 修改項目源
  3. 更換SelectedText與複製
相關問題