【问题标题】:Binding issue in ItemsControl within a UserControl in WPFWPF 中 UserControl 中 ItemsControl 的绑定问题
【发布时间】:2018-03-06 02:21:54
【问题描述】:

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

我有一个用户控件 (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。问题似乎是窗口中的绑定而不是用户控件中的绑定,我绞尽脑汁试图找出原因。

【问题讨论】:

  • @Manfred 我想让用户控件可重用并能够按原样使用 MainWindow 中的绑定。有没有办法修改自定义用户控件,以便 ItemsControl 中的各个复选框可以将其暴露的依赖属性作为用户提供的绑定的目标?
  • @问题不在于控件,问题在于您尝试直接在数据上设置绑定。无论您如何执行此操作,您都必须手动指定 DataContext,因为它不是可视化树的一部分。

标签: c# wpf binding itemscontrol


【解决方案1】:

发生这种情况是因为您的CheckBoxTableData 无法知道您的MainWindowCheckBoxTable 中的 ItemsControl 生成的 CheckBox 都有一个 CheckBoxData 的实例作为它们的数据源。但是,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);

但是,在您的 ViewModel 中处理这个而不是将该属性添加到 MainWindow 会更简洁。

【讨论】:

    猜你喜欢
    • 2011-03-10
    • 1970-01-01
    • 2011-02-27
    • 2010-11-29
    • 1970-01-01
    • 2021-07-19
    • 2016-06-04
    • 2013-04-12
    • 1970-01-01
    相关资源
    最近更新 更多