[英]WPF Binding in ComboBox with UserControl list
在兩個組合框A和B中。A的ItemsSource是“自定義”列表。 B的ItemsSource是UserControl列表。 手動設置SelectedItem時,A組合框可以很好地工作,但是B組合框UI不會顯示所選的項目。 (在調試中,SelectedItem的值映射是正確的,但是組合框B的UI未被更改。)A和B之間的所有其他結構相同。這是什么原因?
MainWindow.xaml
...
<ComboBox ItemsSource="{Binding FruitList}" SelectedItem="{Binding SelectedFruit}"
DisplayMemberPath="FruitName" />
<Button Content="Button" HorizontalAlignment="Left"
VerticalAlignment="Top" Width="75" Click="Button_Click"/>
<ComboBox ItemsSource="{Binding UserControlList}" SelectedItem="{Binding SelectedUserControl}" DisplayMemberPath="ItemName" />
<Button Content="Button" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Click="Button_Click2"/>
</Grid>
MainWindow.xaml.cs
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
FruitList.Add(f1);
FruitList.Add(f2);
FruitList.Add(f3);
UserControlList.Add(u1);
UserControlList.Add(u2);
UserControlList.Add(u3);
}
Fruit f1 = new Fruit { FruitName = "Apple" };
Fruit f2 = new Fruit { FruitName = "Banana" };
Fruit f3 = new Fruit { FruitName = "Lemon" };
MyUserControl u1 = new MyUserControl { ItemName = "Apple" };
MyUserControl u2 = new MyUserControl { ItemName = "Banana" };
MyUserControl u3 = new MyUserControl { ItemName = "Lemon" };
ObservableCollection<Fruit> _FruitList = new ObservableCollection<Fruit>();
public ObservableCollection<Fruit> FruitList
{
get { return _FruitList; }
set
{
_FruitList = value;
OnPropertyChanged();
}
}
Fruit _SelectedFruit;
public Fruit SelectedFruit
{
get { return _SelectedFruit; }
set
{
_SelectedFruit = value;
OnPropertyChanged();
}
}
ObservableCollection<MyUserControl> _UserControlList = new ObservableCollection<MyUserControl>();
public ObservableCollection<MyUserControl> UserControlList
{
get
{
return _UserControlList;
}
set
{
_UserControlList = value;
OnPropertyChanged();
}
}
MyUserControl _SelectedUserControl;
public MyUserControl SelectedUserControl
{
get { return _SelectedUserControl; }
set
{
_SelectedUserControl = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string caller = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(caller));
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.SelectedFruit = f3;
}
private void Button_Click2(object sender, RoutedEventArgs e)
{
this.SelectedUserControl = u3;
}
}
public class Fruit
{
public string FruitName { get; set; }
}
}
用戶控件
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
}
public string ItemName { get; set; }
}
這不是實現此目標的好方法。 更好地為組合框定義ItemTemplate以在其中包含UserControl:
<ComboBox ItemsSource="{Binding ItemList}" SelectedItem="{Binding SelectedItem}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<myControls:MyUserControl/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
並定義類Item
public class Item
{
public string ItemName { get; set; }
}
ObservableCollection<Item> _ItemsList = new ObservableCollection<Item>();
public ObservableCollection<Item> ItemsList
{
get
{
return _ItemsList ;
}
set
{
_ItemsList = value;
OnPropertyChanged();
}
}
這里,您的UserControl的DataContext將是Item
對象。 您可以將ItemName綁定到用戶控件中以隨時顯示它。
在用戶控件中,您可以:
<TextBlock Text="{Binding ItemName}"></TextBlock>
既然您問“原因是什么?”:
第二個組合框不顯示任何選擇的原因是ComboBox
專門處理ContentControl
類型的項目。 在只讀選擇框中,用於顯示值的不是ContentControl
,而是ContentControl
的內容 。 由於UserControl
是ContentControl
,因此UserControl
的內容顯示在選擇框中,因此您丟失了UserControl
的數據上下文; 最后,即使SelectedItem
包含對仍然具有有效數據上下文的UserControl
的引用,也會顯示一個空字符串。 (據我所知,這種行為是未記錄的;但是您可以通過檢查http://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Controls/ComboBox上的ComboBox的代碼來看到它的工作原理.cs ,尤其是UpdateSelectionBoxItem()方法)。
通過在第二個ComboBox上設置IsEditable="True"
,可以看到如果組合框沒有只讀選擇框,則一切正常。
因此,通常應避免將UI元素添加到組合框,尤其是在使用DisplayMemberPath
屬性的情況下,即,如果您從不希望實際顯示UI元素。
@nit的答案描述了顯示具有非標准外觀的ComboBox項的推薦方法(例如,使用UserControls)。
但是,如果您堅持將UserControl
項目列表傳遞到ComboBox,則可以刪除DisplayMemberPath
並使用類似以下內容的方法:
<ComboBox ItemsSource="{Binding UserControlList}" SelectedItem="{Binding SelectedUserControl}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ItemName}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
此外,在UserControl的構造函數中,必須放置以下行:
((FrameworkElement) Content).DataContext = this;
必須確保正確的數據上下文在只讀選擇框中可用,該選擇框中僅包含用戶控件的內容,而不包含用戶控件本身。
請注意,在上面的示例中,下拉列表僅包含文本(即項目名稱),但是選擇框將包含完全呈現的用戶控件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.