WPF 数据绑定问题

发布于 2024-08-17 13:08:46 字数 2886 浏览 4 评论 0原文

我编写了一个非常短的应用程序,其中我试图实现以下目标:让 CheckBox 从代码更改其状态。我已经连接了 INotifyPropertyChanged 接口,并期望看到一些结果,但显然该应用程序什么也没做。数据绑定有问题吗?

Window1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;

namespace WpfTEST
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window, INotifyPropertyChanged
    {
        public Window1()
        {
            InitializeComponent();
            this.Loaded += new RoutedEventHandler(Window1_Loaded);
            this.PropertyChanged += new PropertyChangedEventHandler(Window1_PropertyChanged);
        }

        public bool Flag
        {
            get { return m_flag; }
            set
            {
                m_flag = value; 
                OnPropertyChanged("Flag");
            }
        }

        private bool m_flag = false;

        void Window1_Loaded(object sender, RoutedEventArgs e)
        {
            this.m_cbox.DataContext = this;

            for (int i = 0; i < 1000; i++)
            {
                Flag = (i % 2 == 0);
                Thread.Sleep(200);
            }


        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
        void Window1_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {

        }

        #endregion
    }
}

Window1.xaml

<Window x:Class="WpfTEST.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300" x:Name="window">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0.5*" />
            <ColumnDefinition Width="0.5*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="0.5*" />
            <RowDefinition Height="0.5*" />
        </Grid.RowDefinitions>
        <CheckBox x:Name="m_cbox" Content="Let's see what happens" Grid.Row="2" Grid.Column="2" Grid.RowSpan="1" Grid.ColumnSpan="1" IsChecked="{Binding Path=Flag, ElementName=window, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    </Grid>
</Window>

I've written a very short app in which I'm trying to achieve the following : have the CheckBox change its state from code. I've wired up the INotifyPropertyChanged interface and was expecting to see some results but apparently the app does nothing. Is there something wrong with the databinding?

Window1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;

namespace WpfTEST
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window, INotifyPropertyChanged
    {
        public Window1()
        {
            InitializeComponent();
            this.Loaded += new RoutedEventHandler(Window1_Loaded);
            this.PropertyChanged += new PropertyChangedEventHandler(Window1_PropertyChanged);
        }

        public bool Flag
        {
            get { return m_flag; }
            set
            {
                m_flag = value; 
                OnPropertyChanged("Flag");
            }
        }

        private bool m_flag = false;

        void Window1_Loaded(object sender, RoutedEventArgs e)
        {
            this.m_cbox.DataContext = this;

            for (int i = 0; i < 1000; i++)
            {
                Flag = (i % 2 == 0);
                Thread.Sleep(200);
            }


        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
        void Window1_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {

        }

        #endregion
    }
}

Window1.xaml

<Window x:Class="WpfTEST.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300" x:Name="window">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0.5*" />
            <ColumnDefinition Width="0.5*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="0.5*" />
            <RowDefinition Height="0.5*" />
        </Grid.RowDefinitions>
        <CheckBox x:Name="m_cbox" Content="Let's see what happens" Grid.Row="2" Grid.Column="2" Grid.RowSpan="1" Grid.ColumnSpan="1" IsChecked="{Binding Path=Flag, ElementName=window, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    </Grid>
</Window>

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

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

发布评论

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

评论(2

太阳哥哥 2024-08-24 13:08:46

我在你的代码中看到的唯一真正的问题是 Loaded 中的睡眠循环。这会导致 UI 线程在循环期间无响应,因为您将 UI 线程置于阻塞状态。

有一种更好的方法来测试您是否可以从代码更改标志并让您的绑定生效。在窗口中添加一个按钮,将一个单击处理程序连接到该按钮,然后在该单击处理程序中,切换 Flag ——我对您的原始代码进行了这些修改(并删除了睡眠循环),单击按钮上的 可以按照您想要的方式切换复选框的状态。

<Window x:Class="WpfTEST.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300" x:Name="window">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0.5*" />
            <ColumnDefinition Width="0.5*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="0.5*" />
            <RowDefinition Height="0.5*" />
        </Grid.RowDefinitions>
        <!-- I added this button: -->
        <Button Click="Button_Click" Grid.Row="0" Grid.Column="0"/>
        <CheckBox x:Name="m_cbox" Content="Let's see what happens" Grid.Row="2" Grid.Column="2" Grid.RowSpan="1" Grid.ColumnSpan="1" IsChecked="{Binding Path=Flag, ElementName=window, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    </Grid>
</Window>

并在后面的代码中:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;

namespace WpfTEST {
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window, INotifyPropertyChanged {
        public Window1() {
            InitializeComponent();
            this.Loaded += new RoutedEventHandler(Window1_Loaded);
            this.PropertyChanged += new PropertyChangedEventHandler(Window1_PropertyChanged);
        }

        public bool Flag {
            get { return m_flag; }
            set {
                m_flag = value;
                OnPropertyChanged("Flag");
            }
        }

        private bool m_flag = false;

        void Window1_Loaded( object sender, RoutedEventArgs e ) {
            this.m_cbox.DataContext = this;
            Flag = false;
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged( string name ) {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
        void Window1_PropertyChanged( object sender, PropertyChangedEventArgs e ) {

        }

        #endregion

        private void Button_Click( object sender, RoutedEventArgs e ) {
            Flag = !Flag;
        }
    }
}

除了上述修改以添加按钮及其单击处理程序并删除该睡眠循环之外,我没有对您的原始代码进行任何修改(尽管您可以稍微简化它)。

The only real problem I see with your code is the sleep loop in Loaded. That causes the UI thread to go unresponsive for the duration of the loop, since you're putting the UI thread into a blocked state.

There's a better way to test if you can change the flag from code and have your binding fire. Add a button to the window, hook up a click handler to the button, and in that click handler, toggle Flag -- I made those modifications to your original code (and removed the sleep loop), clicking on the button toggles the checkbox's state in the fashion you seem to desire.

<Window x:Class="WpfTEST.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300" x:Name="window">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0.5*" />
            <ColumnDefinition Width="0.5*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="0.5*" />
            <RowDefinition Height="0.5*" />
        </Grid.RowDefinitions>
        <!-- I added this button: -->
        <Button Click="Button_Click" Grid.Row="0" Grid.Column="0"/>
        <CheckBox x:Name="m_cbox" Content="Let's see what happens" Grid.Row="2" Grid.Column="2" Grid.RowSpan="1" Grid.ColumnSpan="1" IsChecked="{Binding Path=Flag, ElementName=window, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    </Grid>
</Window>

and in code behind:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;

namespace WpfTEST {
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window, INotifyPropertyChanged {
        public Window1() {
            InitializeComponent();
            this.Loaded += new RoutedEventHandler(Window1_Loaded);
            this.PropertyChanged += new PropertyChangedEventHandler(Window1_PropertyChanged);
        }

        public bool Flag {
            get { return m_flag; }
            set {
                m_flag = value;
                OnPropertyChanged("Flag");
            }
        }

        private bool m_flag = false;

        void Window1_Loaded( object sender, RoutedEventArgs e ) {
            this.m_cbox.DataContext = this;
            Flag = false;
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged( string name ) {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
        void Window1_PropertyChanged( object sender, PropertyChangedEventArgs e ) {

        }

        #endregion

        private void Button_Click( object sender, RoutedEventArgs e ) {
            Flag = !Flag;
        }
    }
}

Other than the above modifications to add the button and its click handler, and remove that sleep loop, I made no modifications to your original code (although you could streamline it a bit).

别理我 2024-08-24 13:08:46

仅当您的 Flag 属性是依赖属性时,这才有效。为了以我能想到的最简单的方式使其工作,我会执行以下操作:
将您的绑定更改为:

IsChecked="{Binding Path=Flag,Mode=TwoWay}"

并在后面代码的构造函数中执行以下操作:

DataContext = this;

或在 XAML

DataContext="{BindingrelativeSource={RelativeSource self}}"

中注意:如果将数据上下文设置为窗口,则 Flag 不需要是依赖项属性。

That will only work if your Flag property is a dependency property. To get this working in the simplest way i can think of i would do the following :
change your binding to be :

IsChecked="{Binding Path=Flag,Mode=TwoWay}"

and in your constructor in your code behind do this :

DataContext = this;

or in XAML

DataContext="{Binding RelativeSource={RelativeSource self}}"

Note : Flag does not need to be a dependency property if you are setting the datacontext to be the window.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文