簡體   English   中英

具有用戶控件列表的ComboBox中的WPF綁定

[英]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內容 由於UserControlContentControl ,因此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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM