【问题标题】:Bind a control to a single value in a collection/array in WPF将控件绑定到 WPF 中的集合/数组中的单个值
【发布时间】:2010-01-17 20:19:21
【问题描述】:

在 WPF 中,我有一个 bool 集合?值,我想以编程方式将它们中的每一个绑定到一个单独的复选框。我希望绑定是双向的,以便在代码中更改集合中单个项目的值会更新复选框,反之亦然。

我花了很长时间试图弄清楚如何做到这一点,但我完全陷入了困境。使用以下代码,复选框仅在加载窗口时才获得正确的值,仅此而已。更改复选框甚至不会更新集合中的值。 (更新:这似乎是 .NET4 中的错误,因为该集合确实在相同的 .NET3.5 项目中更新。更新:Microsoft 已确认该错误并将在 .NET4 版本中修复。)

非常感谢您的帮助!

C#:

namespace MyNamespace
{
    public partial class MyWindow : Window, INotifyPropertyChanged
    {
        public MyWindow()
        {
            InitializeComponent();
            DataContext = this;
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
               PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }

        public List<bool?> myCollection = new List<bool?>
            { true, false, true, false, true, false };

        public List<bool?> MyCollection
        {
            get { return myCollection; }
            set { myCollection = value; }
        }
    }
}

XAML:

<CheckBox IsChecked="{Binding Path=MyCollection[0], Mode=TwoWay}">

【问题讨论】:

  • 我仍在处理前 3 个答案,但我对为什么我的代码似乎对前两个受访者有效(至少在 CheckBox -> MyCollection 方向上)感到困惑。对我来说,这根本就没有发生。我正在使用 VS2010 Beta 2 和 .NET4,以防万一。
  • 好吧,我当然认为这无关紧要:我将所有内容都复制到了一个 .NET 3.5 项目中,嘿,很快——CheckBox 更新了 MyCollection 中的值。我想知道为什么它在 .NET 4 中不起作用?
  • 嗯,如果你有这样的代码在 .NET 3.5 中工作,但相同的代码在 .NET 4 中不工作,这表明在 .NET 4 中存在错误。可能值得发布到 Connect .

标签: c# .net wpf data-binding two-way-binding


【解决方案1】:

这里需要更改一些内容才能使其正常工作。首先,您需要将布尔值包装在实现 INotifyPropertyChanged 接口的对象中,以便获得您正在寻找的更改通知。目前,您正在绑定到集合中未实现该接口的布尔值。为此,您可以像这样创建一个包装类:

  public class Wrapper: INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private bool val = false;

        public bool Val
        {
            get { return val; }
            set
            {
                val = value;
                this.OnPropertyChanged("Val");
            }
        }

        public Wrapper(bool val)
        {
            this.val = val;
        }

    }

然后,您需要在表单中创建这些对象,而不是布尔值列表。您可能还希望使用可观察集合而不是列表,以便发送添加和删除项目的通知。如下所示:

public Window1()
    {
        InitializeComponent();
        this.DataContext = this;
    }

    private ObservableCollection<Wrapper> myCollection = new ObservableCollection<Wrapper>()
        {new Wrapper(true), new Wrapper(false), new Wrapper(true)};


    public ObservableCollection<Wrapper> MyCollection
    {
        get { return myCollection; }
    }

接下来要做的是在你的 ui 中显示一个复选框列表。为此,WPF 提供了项目控件。 ListBox 是一个项目控件,因此我们可以将其用作起点。将列表框的 itemssource 设置为 MyCollection。然后我们需要定义每个 Wrapper 对象将如何显示在列表框中,这可以通过在 windows 资源中创建的数据模板来完成。如下所示:

<Window.Resources>
    <DataTemplate x:Key="myCollectionItems">
        <CheckBox IsChecked="{Binding Path=Val, Mode=TwoWay}"></CheckBox>
    </DataTemplate>
</Window.Resources>
<Grid>
    <ListBox ItemsSource="{Binding Path=MyCollection}" ItemTemplate="{StaticResource myCollectionItems}"></ListBox>
</Grid>

这应该让您通过一个简单的复选框演示来启动和运行,这些复选框的值绑定到一个布尔值列表。

【讨论】:

  • -1 尽管您的建议可能有效,但原始发帖人的代码只需要做一件事,将集合类型从 List 更改为 ObservableCollection - 您的答案可能是正确的,但是不是手头的问题。
  • 问题表明需要绑定到复选框列表,这显然比绑定到每个项目更好使用 itemscontrol。该问题还指出代码中的更改应该导致复选框更改,这通过在包装器对象中实现更改通知来证明。据我所知,如果不这样做,更改将不会传递给 UI。
  • 非常感谢这个 Matt - 这种方法肯定会很有用,因为我打算以编程方式创建复选框,而您的回答为此提供了一个优雅的解决方案。
【解决方案2】:

是什么让您认为它不起作用?它对我有用:)

这是我的测试 XAML:

<UniformGrid>
    <CheckBox IsChecked="{Binding Path=MyCollection[0], Mode=TwoWay}"/>
    <ListBox ItemsSource="{Binding MyCollection}"/>
    <Button Content="Test" Click="Button_Click"/>
</UniformGrid>

这是我的代码:

private void Button_Click(object sender, RoutedEventArgs e)
{

}

(其余的和你的一样)

我在Button_Click 上放置了一个断点并检查了MyCollection[0] 它是根据CheckBoxIsChecked 值更新的。

尝试将您的集合类型从 List&lt;bool?&gt; 更改为 ObservableCollection&lt;bool?&gt; 也许这就是您认为它不适合您的原因(事实上,对集合的更改不会反映在您的视图中的其他任何地方)。

【讨论】:

  • 感谢您的回复 Aviad。我在一个新项目中再次尝试了我的代码,只是为了确定,但没有运气。不知道你是怎么做到的!但是,当我将 List 更改为 ObservableCollection 时,代码中值的更改会立即反映在复选框上 - 但反之则不然。但这至少是一个开始。
  • 查看我上面的评论,CheckBox->MyCollection 适用于 .NET3.5 但不适用于 .NET4
【解决方案3】:

将您的 List&lt;bool?&gt; 更改为 ObservableCollection&lt;bool?&gt;。 List 不会引发 WPF 需要更新 UI 的更改通知。 ObservableCollection 可以。这会处理列表条目发生更改并且 CheckBox 需要相应更新的情况。

在另一个方向上,即使使用List&lt;bool?&gt;,它也对我有用——即切换复选框会修改集合中的值。您的绑定语法当然是正确的。

【讨论】:

  • 感谢您的回复。更改为 ObservableCollection 确实会在代码中的值更改时更新 UI。但奇怪的是,另一个方向不适用于我的其余代码保持原样。
  • 查看我上面的评论,CheckBox->MyCollection 适用于 .NET3.5 但不适用于 .NET4
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-16
  • 1970-01-01
  • 2011-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多