選定的項目必須被視爲等於集合中的項目。但是,您始終返回Languages
的新對象集合,因此當選擇更改時,您將ComboBox.ItemsSource
設置爲不包含剛選擇的對象的新集合。因此,ComboBox
將所選項目值丟棄爲無效。正如你發現的那樣,使用SelectedValuePath
不能解決這個問題。
你可以通過重寫Equals(Language)
上Language
通過保持你的Languages
圍繞永久和重用他們解決這個問題,或者(更好)。
如果你需要翻譯Name
屬性,你可以這樣做with a value converter。
我建議不要覆蓋Equals()
的原因是,在C#中,你習慣於假設比較引用類型的兩個實例意味着Object.ReferenceEquals()
,並且打破該假設會導致錯誤。我從經驗講。
由於我們不再使用Name
屬性,我們可以只改變Languages
到語言ID的List<int>
- 在這種情況下,我們可以把它只讀的,從來就不願去重新創建列表。我在這裏完成了。
public class LanguageNameConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[0] is int)
{
var itemLanguageId = (int)values[0];
var displayLanguageId = (int)values[1];
// Do stuff here to get the translated name of the item language
var itemLanguageNameTranslated = $"Name of language {itemLanguageId} in language {displayLanguageId}";
return itemLanguageNameTranslated;
}
else return values[0]?.GetType();
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
XAML:
<ComboBox
SelectedValue="{Binding LanguageId}"
ItemsSource="{Binding Languages}"
>
<ComboBox.ItemTemplate>
<DataTemplate>
<Label>
<Label.Content>
<MultiBinding
Converter="{StaticResource LanguageNameConverter}"
>
<Binding Path="." />
<Binding
Path="DataContext.LanguageId"
RelativeSource="{RelativeSource AncestorType=ComboBox}"
/>
</MultiBinding>
</Label.Content>
</Label>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
如果您更願意保持Language
類Languages
,剛恢復SelectedValuePath="Id"
的組合框,並設置第一Binding
的Path
在MultiBinding
來代替Id
的.
。
<ComboBox
SelectedValue="{Binding LanguageId}"
SelectedValuePath="Id"
...
...
<MultiBinding
Converter="{StaticResource LanguageNameConverter}"
>
<Binding Path="Id" />
<Binding
Path="DataContext.LanguageId"
RelativeSource="{RelativeSource AncestorType=ComboBox}"
/>
</MultiBinding>
等號清除溶液
這裏的Equals()
解決方案;我們嘗試了它,但是在選擇更改之後,保留舊的SelectedItem並且舊的名稱以先前選擇的語言存在問題。這是因爲Equals()
覆蓋的事情。所以我們使用了多值轉換器,它不需要任何解決方法或有趣的業務。
只是做事情WPF希望的方式,沒有人受傷。這是規則。
public class Language
{
public int Id { get; set; }
public String Name { get; set; }
public override bool Equals(object obj)
{
if (obj is Language)
{
return ((Language)obj).Id == Id;
}
return base.Equals(obj);
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
如果你選擇了這個方案,你還需要一個遞歸後衛添加到您的LanuageId
屬性:
private int _languageId;
public int LanguageId
{
get
{
return _languageId;
}
set
{
if (_languageId != value)
{
_languageId = value;
OnPropertyChanged("Languages");
OnPropertyChanged();
}
}
}
更換ComboBox.ItemsSource
現在將導致實際SelectedItem
改變到一個新的對象實例,其中更新SelectedValue
,這將導致LanguageId
再次被設置 - 它已經具有相同的值。如果你省略了遞歸守護,LanguageId
的set
塊會再次提升PropertyChanged
爲Languages
,這將會更新SelectedItem
等等 - 並且在堆棧溢出之前我們已經進入比賽。
爲什麼你需要這個? '''NotifyPropertyChanged(「Languages」);''' – tym32167
所選項目必須等於集合中的一個項目。您總是從'語言'中返回一個新對象的集合,所以當選擇改變時,您將ItemsSource設置爲一個新的集合,該集合不包含剛剛選擇的對象。所以ComboBox將所選項目的值丟棄爲無效。你可以通過在'Language'上重寫'Equals(Language)'來解決這個問題,或者(通過保持你的'語言'永久化並重用它們來更好地解決這個問題。 –
我需要這樣做,因爲我以這種方式更改了應用程序的語言,並且組合框中的項目也需要進行翻譯。 –