将ObservableCollection <>类型传递为依赖项属性

时间:2020-05-10 11:05:20

标签: c# xaml uwp uwp-xaml

我正在尝试创建一个多选Combobox自定义控件,此自定义控件应该公开一个名为DropDownDataSource的依赖项属性,控件的用户可以通过该属性来决定绑定到ComboBox的日期。我的代码如下:

MainPage.Xaml

<Grid>
    <local:CustomComboBox x:Name="customcb" DropDownDataSource="{x:Bind DropDownDataSource, Mode=OneWay}"  Loaded="CustomControl_Loaded"> </local:CustomComboBox>
</Grid>

MainPage.Xaml.cs

public sealed partial class MainPage : Page, INotifyPropertyChanged
{
    private ObservableCollection<Item> _dropDownDataSource;
    public ObservableCollection<Item> DropDownDataSource
    {
        get => _dropDownDataSource;
        set
        {
            _dropDownDataSource = value;
            OnPropertyChanged();
        }
    }

    public MainPage()
    {
        this.InitializeComponent();
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName]string name = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
    private void CustomControl_Loaded(object sender, RoutedEventArgs e)
    {

       
        var Items = new ObservableCollection<Item>(Enumerable.Range(1, 10)
              .Select(x => new Item
              {
                  Text = string.Format("Item {0}", x),
                  IsChecked = x == 40 ? true : false
              }));
        DropDownDataSource = Items;
    
    }
}

模型

    public class Item : BindableBase
{
    public string Text { get; set; }

    bool _IsChecked = default;
    public bool IsChecked { get { return _IsChecked; } set { SetProperty(ref _IsChecked, value); } }
}

public abstract class BindableBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void SetProperty<T>(ref T storage, T value,
        [System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
    {
        if (!object.Equals(storage, value))
        {
            storage = value;
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    protected void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

CustomUserControl XAML

  <Grid x:Name="GrdMainContainer">
   
    <StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center">
        <TextBox Width="200" FontSize="24" Text="{Binding Header, Mode=TwoWay}" 
             IsReadOnly="True" TextWrapping="Wrap" MaxHeight="200" />
        <ScrollViewer VerticalScrollBarVisibility="Auto" MaxHeight="200" Width="200" Background="White">
            <ItemsControl ItemsSource="{Binding Items}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <CheckBox Content="{Binding Text}" 
                      FontSize="24" 
                      Foreground="Black"
                      IsChecked="{Binding IsChecked, Mode=TwoWay}" 
                      IsThreeState="False" />
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </ScrollViewer>
    </StackPanel>
</Grid>

CustomUserControl Cs文件

    public sealed partial class CustomComboBox : UserControl
{
    public CustomComboBox()
    {
        this.InitializeComponent();

    }
    public ObservableCollection<Item> DropDownDataSource
    {
        get { return (ObservableCollection<Item>)GetValue(DropDownDataSourceProperty); }
        set { SetValue(DropDownDataSourceProperty, value); }
    }

    public static readonly DependencyProperty DropDownDataSourceProperty =
        DependencyProperty.Register("DropDownDataSource", typeof(ObservableCollection<Item>), typeof(CustomComboBox), new PropertyMetadata("", HasDropDownItemUpdated));
    private static void HasDropDownItemUpdated(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is CustomComboBox ucrcntrl)
        {
            var grd = UIElementExtensions.FindControl<Grid>(ucrcntrl, "GrdMainContainer");
            grd.DataContext = ucrcntrl.DropDownDataSource as ObservableCollection<Item>;
        }
    }

}

对我来说一切都很好,但是由于某种原因,下拉列表变空了。如果我直接将视图模型分配给Control,则可以正常运行,而不是依赖属性。但是在我的条件下,必须在用户控件上具有诸如DataSource,SelectedIndex等的属性,供最终用户使用。谁能指出这里出了什么问题? Here,我已附上完整代码的副本。

1 个答案:

答案 0 :(得分:1)

我下载了您的示例代码,问题应该出在绑定中。

<ItemsControl ItemsSource="{Binding Items}">

不推荐这种书写方式。在ObservableCollection中,Items是受保护的属性,不适合用作绑定属性。

您可以尝试直接在ItemsControl中绑定依赖项属性:

<ItemsControl ItemsSource="{x:Bind DropDownDataSource,Mode=OneWay}">
    <ItemsControl.ItemTemplate>
        <DataTemplate x:DataType="local:Item">
            <CheckBox IsChecked="{x:Bind IsChecked, Mode=TwoWay}" 
                      IsThreeState="False" >
                <TextBlock Text="{x:Bind Text}" Foreground="Black" FontSize="24"/>
            </CheckBox>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

此外,您可能已经注意到我修改了CheckBox的样式并将内容重写为TextBlock,因为在默认样式CheckBox中,Foreground是不受内部ContentPresenter的约束。

谢谢。