GridView 中的两种方式数据绑定

发布于 2024-07-12 19:36:15 字数 3123 浏览 10 评论 0原文

我们有一个应用程序,它使用简单的单向绑定 GridView 来显示一些数据。 好吧,现在我们需要允许用户更改其中一些数据,因此我一直在尝试在 GridView 中使用两种方式的数据绑定。 到目前为止,一切都显示正确,但在 GridView 中编辑单元格似乎根本不起作用。 我搞砸了什么? 像这样的两种方式数据绑定是否可能? 我是否应该开始将所有内容转换为使用不同的控件,例如 DataGrid?

我编写了一个小型测试应用程序来显示我的问题。 如果您尝试一下,您会发现属性设置器在初始化后永远不会被调用。

XML:

    Title="Window1" Height="300" Width="300">
    <Grid>
        <ListView Name="TestList">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Strings">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBox Text="{Binding Path=String, Mode=TwoWay}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Header="Bools">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <CheckBox IsChecked="{Binding Path=Bool, Mode=TwoWay}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

这是相应的代码:

using System.Collections.Generic;
using System.Windows;

namespace GridViewTextbox
{
    public partial class Window1 : Window
    {
        private List<TestRow> _rows = new List<TestRow>();

        public Window1()
        {
            InitializeComponent();

            _rows.Add(new TestRow("a", false));
            _rows.Add(new TestRow("b", true));
            _rows.Add(new TestRow("c", false));

            TestList.ItemsSource = _rows;
            TestList.DataContext = _rows;
        }
    }

    public class TestRow : System.Windows.DependencyObject
    {
        public TestRow(string s, bool b)
        {
            String = s;
            Bool = b;
        }

        public string String
        {
            get { return (string)GetValue(StringProperty); }
            set { SetValue(StringProperty, value); }
        }

        // Using a DependencyProperty as the backing store for String.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty StringProperty =
            DependencyProperty.Register("String", typeof(string), typeof(TestRow), new UIPropertyMetadata(""));


        public bool Bool
        {
            get { return (bool)GetValue(BoolProperty); }
            set { SetValue(BoolProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Bool.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty BoolProperty =
            DependencyProperty.Register("Bool", typeof(bool), typeof(TestRow), new UIPropertyMetadata(false));
    }
}

We have an app that uses simple one way binding with a GridView to display some data. Well, now we need to allow the user to change some of that data, so I've been trying to get two way data binding to work in the GridView. So far everything displays correctly, but editing cells in the GridView seems to do nothing at all. What am I messing up? Is two way databinding like this even possible? Should I just start converting everything to use a different control, like maybe a DataGrid?

I wrote a tiny test app that shows my problem. If you try it, you'll see that the property setters never get called after their initialization.

Xaml:

    Title="Window1" Height="300" Width="300">
    <Grid>
        <ListView Name="TestList">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Strings">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBox Text="{Binding Path=String, Mode=TwoWay}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Header="Bools">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <CheckBox IsChecked="{Binding Path=Bool, Mode=TwoWay}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

And here's the corresponding code:

using System.Collections.Generic;
using System.Windows;

namespace GridViewTextbox
{
    public partial class Window1 : Window
    {
        private List<TestRow> _rows = new List<TestRow>();

        public Window1()
        {
            InitializeComponent();

            _rows.Add(new TestRow("a", false));
            _rows.Add(new TestRow("b", true));
            _rows.Add(new TestRow("c", false));

            TestList.ItemsSource = _rows;
            TestList.DataContext = _rows;
        }
    }

    public class TestRow : System.Windows.DependencyObject
    {
        public TestRow(string s, bool b)
        {
            String = s;
            Bool = b;
        }

        public string String
        {
            get { return (string)GetValue(StringProperty); }
            set { SetValue(StringProperty, value); }
        }

        // Using a DependencyProperty as the backing store for String.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty StringProperty =
            DependencyProperty.Register("String", typeof(string), typeof(TestRow), new UIPropertyMetadata(""));


        public bool Bool
        {
            get { return (bool)GetValue(BoolProperty); }
            set { SetValue(BoolProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Bool.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty BoolProperty =
            DependencyProperty.Register("Bool", typeof(bool), typeof(TestRow), new UIPropertyMetadata(false));
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

以可爱出名 2024-07-19 19:36:17

如果属性设置器是依赖属性,则不会从 WPF 调用它们。 它们被用作 CLR 的便利,并由不知道 DependencyProperty 的代码调用。

WPF 代码可以:

yourControl.SetValue(TestRow.StringProperty, someValue);

不:

yourControl.String = someValue;

您需要挂钩 DepedencyPropertyChanged 事件才能听到更改。

The property setters will NOT be called from WPF if they are dependency properties. Those are used as CLR conveniences and get called by code which is not aware of DependencyProperty.

The WPF code will do:

yourControl.SetValue(TestRow.StringProperty, someValue);

Not:

yourControl.String = someValue;

You need to hook the DepedencyPropertyChanged event to hear the changes.

守护在此方 2024-07-19 19:36:17

当您使用依赖属性时,Setter 不会被绑定调用,而是直接更改值(使用 SetValue 或类似的东西)。

尝试添加 PropertyChangedCallback,并在其中设置断点以查看 GridView 中的值是否发生更改。

public static readonly DependencyProperty BoolProperty =
    DependencyProperty.Register("Bool", typeof(bool), typeof(TestRow), new UIPropertyMetadata(false, OnBoolChanged));
private static void OnBoolChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
    //this method will be called everytime Bool changes value
}

When you use Dependency Properties, the Setters will not be called by bindings, instead they change the value directly (using SetValue or something similar).

Try adding a PropertyChangedCallback, and set a breakpoint in there to see if the value is changed from the GridView.

public static readonly DependencyProperty BoolProperty =
    DependencyProperty.Register("Bool", typeof(bool), typeof(TestRow), new UIPropertyMetadata(false, OnBoolChanged));
private static void OnBoolChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
    //this method will be called everytime Bool changes value
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文