自定义WPF Combobox"应用程序进入中断模式"

时间:2018-04-01 18:31:52

标签: c# wpf xaml mvvm datatemplate

我正在尝试按照示例WPF Datagrid as Combobox 2

创建自定义组合框

我从上面的链接下载了示例项目。然后从Nuget安装了Extended WPF Toolkit,我就可以运行该演示了。但是当我单击组合框中的向下箭头(togglebutton)时,应用程序崩溃,VS2017显示中断模式。

下面是我的ExtendedCombobox类,

public class ExtendedComboBox : ComboBox
{
    #region Dependency Properties

    public static readonly DependencyProperty PopupContentProperty =
        DependencyProperty.Register("PopupContent", typeof(UIElement), typeof(ExtendedComboBox));

    public UIElement PopupContent
    {
        get { return (UIElement)GetValue(PopupContentProperty); }
        set { SetValue(PopupContentProperty, value); }
    }

    #endregion

    #region Constructor

    static ExtendedComboBox()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(ExtendedComboBox), new FrameworkPropertyMetadata(typeof(ExtendedComboBox)));
    }

    #endregion
}

下面是ExtendedDatagridCombobox,

public class ExtendedComboBoxDataGrid : ExtendedComboBox
{
    #region Private Fields

    private readonly DataGrid _dataGrid;

    #endregion

    #region Dependency Properties

    public static readonly DependencyProperty ColumnsProperty = DependencyProperty.Register("Columns",
        typeof(ObservableCollection<DataGridColumn>), typeof(ExtendedComboBoxDataGrid));

    public ObservableCollection<DataGridColumn> Columns
    {
        get => (ObservableCollection<DataGridColumn>)GetValue(ColumnsProperty);
        set => SetValue(ColumnsProperty, value);
    }

    #endregion

    #region Constructors

    public ExtendedComboBoxDataGrid()
    {
        _dataGrid = new DataGrid
        {
            IsReadOnly = true,
            AutoGenerateColumns = false
        };

        var relativeSource = new RelativeSource(RelativeSourceMode.FindAncestor,
            typeof(ExtendedComboBoxDataGrid), 1);

        // Bind ItemsSource
        var itemsSourceBinding = new Binding("ItemsSource") {RelativeSource = relativeSource};
        _dataGrid.SetBinding(ItemsSourceProperty, itemsSourceBinding);

        // Bind SelectedItem
        Binding selectedItemBinding = new Binding("SelectedItem") {RelativeSource = relativeSource};
        _dataGrid.SetBinding(SelectedItemProperty, selectedItemBinding);

        _dataGrid.SelectionChanged += DataGrid_SelectionChanged;

        PopupContent = _dataGrid;

        Columns = new ObservableCollection<DataGridColumn>();
        Columns.CollectionChanged += Columns_CollectionChanged;
    }

    #endregion

    #region Overrides

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        if (GetTemplateChild("PART_EditableTextBox") is TextBox editableTbx)
        {
            editableTbx.TextChanged += EditableTbx_TextChanged;
        }
    }

    #endregion

    #region Private Methods

    private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        IsDropDownOpen = false;
    }

    private void Columns_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null)
        {
            foreach (DataGridColumn column in e.NewItems)
            {
                _dataGrid.Columns.Add(column);
            }
        }

        if (e.OldItems != null)
        {
            foreach (DataGridColumn column in e.OldItems)
            {
                _dataGrid.Columns.Remove(column);
            }
        }
    }

    private void EditableTbx_TextChanged(object sender, TextChangedEventArgs e)
    {
        TextBox editableTbx = (TextBox)sender;
        IsDropDownOpen = true;
        _dataGrid.Items.Filter = o =>
        {
            var properties = o.GetType().GetProperties();
            return properties.Select(p => p.GetValue(o, null)).Any(value => value.ToString().ToLower().Contains(editableTbx.Text));
        };
    }

    #endregion
}

下面是我使用控件的xaml,

<Window
x:Class="DemoApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:CustomControls;assembly=CustomControls"
xmlns:local="clr-namespace:DemoApp"
xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:toolkit="http://schemas.microsoft.com/wpf/2008/toolkit"
Title="MainWindow"
Width="300"
Height="300">
<Grid>
    <Grid.Resources>
        <local:Customers x:Key="Customers" />
    </Grid.Resources>
    <controls:ExtendedComboBoxDataGrid
        Width="250"
        HorizontalAlignment="Center"
        VerticalAlignment="Center"
        IsEditable="True"
        ItemsSource="{StaticResource Customers}"
        SelectedItem="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
                                                              AncestorType={x:Type Window}},
                               Path=SelectedCustomer}"
        StaysOpenOnEdit="True">
        <controls:ExtendedComboBoxDataGrid.Columns>
            <toolkit:DataGridTextColumn Binding="{Binding Name}" Header="Name" />
            <toolkit:DataGridTextColumn Binding="{Binding Address}" Header="Address" />
            <toolkit:DataGridTextColumn Binding="{Binding TelephoneNumber}" Header="Telephone No." />
        </controls:ExtendedComboBoxDataGrid.Columns>
        <controls:ExtendedComboBoxDataGrid.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Margin="4,0" Text="{Binding Path=Name}" />
                    <TextBlock Margin="4,0" Text="{Binding Path=Address}" />
                    <TextBlock Margin="4,0" Text="{Binding Path=TelephoneNumber}" />
                </StackPanel>
            </DataTemplate>
        </controls:ExtendedComboBoxDataGrid.ItemTemplate>
    </controls:ExtendedComboBoxDataGrid>
</Grid>

代码背后,

 public partial class MainWindow : Window, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private Customer selectedCustomer;

    public Customer SelectedCustomer
    {
        get
        {
            return selectedCustomer;
        }
        set
        {
            if (object.ReferenceEquals(selectedCustomer, value) != true)
            {
                selectedCustomer = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("SelectedCustomer"));
                }
            }
        }
    }

    public MainWindow()
    {
        InitializeComponent();
    }
}

下面是我点击的组合框箭头, enter image description here

点击向下箭头时出现以下错误: 对Automation Peer API的递归调用无效。&#39;

1 个答案:

答案 0 :(得分:0)

显然WPF Toolkit控件自动化属性存在一些问题,所以我不得不重写Datagrid控件的OnCreateAutomationPeer()方法。

public class ExtendedDataGrid : DataGrid
{
    protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer()
    {
        return null;
    }
}