wpf 无法成功将元组的ObservableCollection绑定到XAML(VS扩展)

ufj5ltwl  于 2023-05-08  发布在  其他
关注(0)|答案(1)|浏览(205)

在Visual Studio 2022扩展中很难将ObservableCollection的元组绑定到XAML。
我至少部分地尝试遵循this tutorial,尽管它并没有完全做同样的事情。

  • 我设置了一个ObservableCollectionproperty命名元组。
  • 我用两个这样的元组初始化该集合。
  • 我将DataContext设置为this扩展的UserControl
  • DataContext必须是一个对象,这个对象是我们GUI的“ViewModel”,所有的数据绑定都将在这个对象上完成。如果我们使用的数据不是全部组合到一个类中,而是作为我们的MainWindow的属性存在,我们将DataContext设置为MainWindow本身:
  • 我在C#中设置了我的ItemsControlItemsSource
  • 我绑定到XAML中的命名元组(seems like fair game)的属性。
  • <Checkbox Foreground="LightGreen" Content="{Binding Name}" IsChecked="{Binding IsChecked}"></CheckBox>

结果:
我得到两个CheckBox,没有Content

C#

public partial class MyWindowControl : UserControl
    {

        private ObservableCollection<(string Name, bool IsChecked)> ChutzpahItems { get; set; } =
            new ObservableCollection<(string Name, bool IsChecked)>()
            {
                ("Thy Smy Name", true),
                ("Thy Smy OtherName", true),
            };

        /// <summary>
        /// Initializes a new instance of the <see cref="MyWindowControl"/> class.
        /// </summary>
        public MyWindowControl()
        {
            DataContext = this;
            this.InitializeComponent();
            this.itcChutzpah.ItemsSource = ChutzpahItems;
            CheckForPrereqs();
        }
// ...

XAML

<UserControl x:Class="MyWindowExtension.MyWindowControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:vsshell="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.15.0"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300"

             Name="MyToolWindow">

    <Grid>
        <DockPanel>
            <StackPanel
                DockPanel.Dock="Top"
                Orientation="Vertical"
            >
<!-- some other widget stuff removed. -->

                <ItemsControl Name="itcChutzpah">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <StackPanel>
                                <CheckBox
                                    Foreground="LightGreen"
                                    Content="{Binding Name}"
                                    IsChecked="{Binding IsChecked}"
                                ></CheckBox>
                            </StackPanel>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </StackPanel>

<!-- some other widget stuff removed. -->
        </DockPanel>
    </Grid>
</UserControl>

我的意思是很明显我得到了一个绑定的集合,但我的绑定有错误的路径或什么的。
两个问题:
1.我做错了什么?
1.我应该如何调试这个?

c0vxltue

c0vxltue1#

我要把@Yarik的评论作为一个wiki答案放在这里。@克莱门斯也指向了同样的答案。
如果有谁想加答案,我就删掉这个。

调试绑定

正如@Yarik和@Clemens所提到的,Debug >>> Windows >>> XAML Binding Failures是一个很好的调试源代码。
该窗口显示了这个,这表明我们没有绑定,因为Name & IsChecked不是属性,正如注解所警告的那样。

Severity    Count   Data Context    Binding Path    Target              Target Type    Description    
Error       2       ValueTuple`2    Name            CheckBox.Content    Object         Name property not found on object of type ValueTuple`2.
Error       2       ValueTuple`2    IsChecked       CheckBox.IsChecked  Nullable`1     IsChecked property not found on object of type ValueTuple`2.

ValueTuple与元组

正如@Yarik和@Clemens提到的:
从tuple类型的文档来看,似乎是名称生成字段,而不是属性。
和/或
Tuple<,>ValueTuple<,>不同。第一个是一个带属性的类(所以可以与绑定一起使用),第二个是一个带字段的结构。
由于XAML需要绑定属性,ValueTuple将无法工作。

不,真的,您不能使用ValueTuples

这意味着,仅仅因为有Item1Item2,就简单地去掉名称,期望行为与Bind wpf listbox to ObservableCollection of tuples中讨论的行为相匹配,也是行不通的。还是值元组
也就是说

private ObservableCollection<(string, bool)> ChutzpahItems { get; set; } =
    new ObservableCollection<(string, bool)>()
    {
        ("Thy Smy Name", true),
        ("Thy Smy OtherName", true),
    };

和/或

<CheckBox
    Foreground="LightGreen"
    Content="{Binding Item1}"
    IsChecked="{Binding Item2}"
></CheckBox>

......也会出现同样的错误。

Severity    Count   Data Context    Binding Path    Target              Target Type   Description
Error           4   ValueTuple`2    Item1           CheckBox.Content    Object        Item1 property not found on object of type ValueTuple`2.          
Error           4   ValueTuple`2    Item2           CheckBox.IsChecked  Nullable`1    Item2 property not found on object of type ValueTuple`2.

使用老式元组

使用老式的Tuple<string, bool>确实有效,(one caveatan explanation)就像@Yarik和@Clements预测的那样。

private ObservableCollection<Tuple<string, bool>> ChutzpahItems { get; set; } =
    new ObservableCollection<Tuple<string, bool>>()
    {
        new Tuple<string, bool>("Thy Smy Name", true),
        new Tuple<string, bool>("Thy Smy OtherName", true),
    };
<CheckBox
    Foreground="LightGreen"
    Content="{Binding Item1}"
    IsChecked="{Binding Item2, Mode=OneWay}"
></CheckBox>

现在你看到了。

有更好的方法

当然,更好的方法是创建一个
1.具有命名属性和
1.不像元组那样是只读的。

public class CheckboxInfo
{
    public string Name { get; set; }
    public bool IsChecked { get; set; }

    public CheckboxInfo(string name, bool isChecked)
    {
        Name = name;
        IsChecked = isChecked;
    }
}

这正好说明了“* 有时“只是数据”是正确的事情 *",但是,我想斯基特会同意,大多数时候它不是。

相关问题