在WPF中的UserControl中的ItemsControl中绑定问题

时间:2018-03-06 02:21:54

标签: c# wpf binding itemscontrol

我创建了一个简单的示例,它通过更大的用户控件 - 应用程序交互来复制我遇到的问题。控件已更改为简化,但反映了确切的问题。

我有一个用户控件(CheckBoxTable),它根据属性CheckBoxData创建一个复选框网格:

<UserControl
    x:Class="WPFNotWorkingTest.CheckBoxTable"
    x:Name="CheckBoxTableName">
    <ItemsControl DataContext="{Binding ElementName=CheckBoxTableName}" ItemsSource="{Binding CheckBoxData}">
        <ItemsControl.ItemContainerStyle>
            <Style>
                <Setter Property="Grid.Row" Value="{Binding GridRow}" />
                <Setter Property="Grid.Column" Value="{Binding GridColumn}" />
            </Style>
        </ItemsControl.ItemContainerStyle>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Grid ShowGridLines="True" Style="{Binding Path=Style}" Loaded="OnGrid_Loaded"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <CheckBox IsChecked="{Binding IsCheckBoxChecked}"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</UserControl>

ItemSource CheckBoxData是CheckBoxTable用户控件中的ObservableCollection。

public ObservableCollection<CheckBoxTableData> CheckBoxData
{
    get { return (ObservableCollection<CheckBoxTableData>)GetValue(CheckBoxDataProperty); }
    set { SetValue(CheckBoxDataProperty, value); }
}

// Using a DependencyProperty as the backing store for CheckBoxData.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty CheckBoxDataProperty =
     DependencyProperty.Register("CheckBoxData", typeof(ObservableCollection<CheckBoxTableData>), typeof(CheckBoxTable), new PropertyMetadata(null, new PropertyChangedCallback(CheckBoxTable.OnCheckBoxData_Changed)));

private static void OnCheckBoxData_Changed(DependencyObject dObject, DependencyPropertyChangedEventArgs e)
{
    CheckBoxTable table = (CheckBoxTable)dObject;
    ObservableCollection<CheckBoxTableData> objOldValue = (ObservableCollection<CheckBoxTableData>)e.OldValue;
    if (objOldValue != null)
    {
        objOldValue.CollectionChanged -= table.OnTableData_CollectionChanged;
    }

    ObservableCollection<CheckBoxTableData> objNewValue = (ObservableCollection<CheckBoxTableData>)e.NewValue;
    if (objNewValue != null)
    {
        objNewValue.CollectionChanged += table.OnTableData_CollectionChanged;
    }
}

CheckBoxTableData类

    public class CheckBoxTableData : DependencyObject
    {
        public bool? IsCheckBoxChecked
        {
            get { return (bool?)GetValue(IsCheckBoxCheckedProperty); }
            set { SetValue(IsCheckBoxCheckedProperty, value); }
        }
        // Using a DependencyProperty as the backing store for IsCheckBoxChecked.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsCheckBoxCheckedProperty =
             DependencyProperty.Register("IsCheckBoxChecked", typeof(bool?), typeof(CheckBoxTableData), new PropertyMetadata(true));

        public int GridRow
        {
            get { return (int)GetValue(GridRowProperty); }
            set { SetValue(GridRowProperty, value); }
        }

        // Using a DependencyProperty as the backing store for GridRow.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty GridRowProperty =
             DependencyProperty.Register("GridRow", typeof(int), typeof(CheckBoxTableData), new PropertyMetadata(0));

        public int GridColumn
        {
            get { return (int)GetValue(GridColumnProperty); }
            set { SetValue(GridColumnProperty, value); }
        }

        // Using a DependencyProperty as the backing store for GridColumn.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty GridColumnProperty =
             DependencyProperty.Register("GridColumn", typeof(int), typeof(CheckBoxTableData), new PropertyMetadata(0));
    }
}

在窗口中使用:

<Window x:Class="WPFNotWorkingTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WPFNotWorkingTest"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Button Content="Click Me" Click="Button_Click" Margin="5"/>
        <local:CheckBoxTable Grid.Row="1" CheckBoxPerRow="10">
            <local:CheckBoxTable.CheckBoxData>
                <local:CheckBoxTableData IsCheckBoxChecked="True"/>
                <local:CheckBoxTableData IsCheckBoxChecked="False"/>
                <local:CheckBoxTableData IsCheckBoxChecked="{Binding CheckMyBinding}"/>
            </local:CheckBoxTable.CheckBoxData>
        </local:CheckBoxTable>
    </Grid>
</Window>

MainWindow.cs

public partial class MainWindow : Window
{
    public bool? CheckMyBinding
    {
        get { return (bool?)GetValue(CheckMyBindingProperty); }
        set { SetValue(CheckMyBindingProperty, value); }
    }

    // Using a DependencyProperty as the backing store for CheckMyBinding.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty CheckMyBindingProperty =
         DependencyProperty.Register("CheckMyBinding", typeof(bool?), typeof(MainWindow), new PropertyMetadata(false));


    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        if (CheckMyBinding == true)
        {
            CheckMyBinding = false;
        }
        else
        {
            CheckMyBinding = true;
        }
    }
}

单击按钮并执行处理程序不会切换CheckBox的IsChecked。问题似乎是窗口中的绑定而不是用户控件,我已经破坏了我的大脑试图找出原因。

1 个答案:

答案 0 :(得分:0)

这是因为您的CheckBoxTableData无法了解您的MainWindow。由CheckBoxTable中的ItemsControl生成的CheckBoxes都有一个CheckBoxData实例作为其DataSource。但是CheckBoxTableData没有自己的DataContext,您不能使用RelativeSource,因为它们不属于您应用程序的可视化或逻辑树。

XAML设计师可能会让它看起来像是有效的(显示自动完成和所有),但这只是因为它不知道你的控件是如何工作的。

您可以通过在代码中手动设置此绑定来解决此问题:

CheckBoxTableData tableData = new CheckBoxTableData();
BindingOperations.SetBinding(tableData, CheckBoxTableData.IsCheckBoxCheckedProperty,
    new Binding("CheckMyBinding") {Source = this}); // this = MainWindow

checkBoxTable.CheckBoxData = new ObservableCollection<CheckBoxTableData>();
checkBoxTable.CheckBoxData.Add(tableData);

Button toggling CheckBox

然而,在ViewModel中处理此问题会更加清晰,而不是将该属性添加到MainWindow。