【问题标题】:Single-Variable Binding in Win Forms: What am I doing wrong?Win 表单中的单变量绑定:我做错了什么?
【发布时间】:2016-02-18 02:12:52
【问题描述】:

我一直在尝试对 WinForm 中的两个标签进行绑定,但我似乎无法弄清楚我做错了什么。目前,我正在实现INotifyPropertyChanged 接口,并将其绑定到表单中的几个属性。受此影响的当前类是SessionForm.cs(实际形式)和Session.cs(我保存程序所有信息的地方)。有问题的标签在任何一个类中都没有提到,L_No,它保存音符在音阶中的数字引用,以及 L_Note,它保存本能音符值(例如 C、C# 等)。

请允许我解释一下类中的所有内容。该程序旨在通过根据您选择的音阶询问您音阶的第 nth 个音符是什么来测试您的音阶知识。您可以使用表单上的按钮做出选择。

这些选择记录在 Session 类中,该类已被编辑以使其更加简洁。整数数组保存与比例数组相关的音符索引,该数组位于Scale 对象中。例如,典型的Note 数组可能包含以下值:{1,3,0,2,6,1,3,...}。通过使用 Scale 对象中的数组作为参考,这些将转换为音符(例如 D、F、C、E、B、D、F ......)。玩家的选择存储在NoteData 对象的数组中。

SessionForm.cs 中,随着时间的推移,我正在操纵这些信息。每次做出或不做出选择时(取决于他们是否及时猜测),两个标签的值都会改变:L_No 和 L_Note。这两个标签分别由变量 NoteIndex 和 LastNote 操作。当这些值发生变化时,会发生 NotifyPropertyChanged,然后标签应该被更新......但他们没有这样做。

现在,在表单的设计部分,在“属性”窗口中,我将每个标签的 Text 属性设置为绑定到表单内各自的变量,并设置为在属性更改时更新,但似乎没有正在工作。

那我做错了什么?

Session.cs

    public class Session
    {
        public struct NoteData
        {
            public int Note;
            public bool Correct;
            public int GuessTime;
        }

        public Scale Scale;

        /// <summary>
        /// Holds the notes for one game
        /// </summary>
        public int[] Notes { get; private set; }

        public NoteData[] Data { get; private set; }

        /// <summary>
        /// Creates a  Session
        /// </summary>
        /// <param name="difficulty">The difficult of the session, refer to the Resources Class for determination.</param>
        /// <param name="scale_used">The scale to be used. Refer to the Resources Class for determination.</param>
        /// <param name="notes">The notes being used within this Session</param>
        public Session(Resources.Difficulties difficulty, Scale scale_used, int[] notes)
        {
            ID = DateTime.Now;
            Diff = difficulty;
            Scale = scale_used;
            Notes = notes;
            Data = new NoteData[notes.Length];
            internalIndex = 0;
        }

        /// <summary>
        /// Stores Note input for each guessed
        /// </summary>
        /// <param name="index">The index of the note the player is currently on</param>
        /// <param name="correct">Was the guess correct?</param>
        /// <param name="remaining_time">How long did it take for them to guess?</param>
        public void StoreNoteInput(int index, bool correct, int remaining_time)
        {
            if (internalIndex < Data.Length)
                Data[internalIndex++] = new NoteData(index, remaining_time, correct);
        } 


}

SessionForm.cs

    public partial class SessionForm : Form, INotifyPropertyChanged
    {
        public Session curSession { get; private set; }
        Resources.Notes last_note;
        /// <summary>
        /// The note index number in relation to the scale
        /// </summary>
        public int NoteIndex
        {
            get
            { return note_index; }
            private set
            {
                if (note_index != value)
                {
                    note_index = value;
                    NotifyPropertyChanged("NoteIndex");
                }
            }
        }
        /// <summary>
        /// Represents the previous note being tested
        /// </summary>
        public Resources.Notes LastNote
        {
            get
            {
                return last_note;
            }
            private set
            {
                if (last_note != value)
                {
                    last_note = value;
                    NotifyPropertyChanged("LastNote");
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;

        private void TickDownTimer_Tick(object sender, EventArgs e)
        {
            remainingTime -= countingDown ? 1000 : 100;
            if (remainingTime == 0)
            {
                if (countingDown)
                {
                    countingDown = false;
                    TickDownTimer.Interval = 100;
                }
                if (curIndex > 0)
                {
                    //you ran out of time on the last note
                    RecordNoteInput(curIndex - 1, false);


                }
                NextNote();
            }
            SetTimerText();
        }

        private void RecordNoteInput(int index, bool correct)
        {
            curSession.StoreNoteInput(index, correct, remainingTime);
            NoteIndex = curSession.Notes[curIndex - 1];
            LastNote = curSession.Scale.Notes[NoteIndex];
            L_Note.ForeColor = correct ? Color.Green : Color.Red;
        }

        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

更新:这是来自SessionForm.Designer.cs的绑定代码:

            this.sessionFormBindingSource1 = new System.Windows.Forms.BindingSource(this.components);
            this.sessionFormBindingSource2 = new System.Windows.Forms.BindingSource(this.components);
            this.sessionFormBindingSource = new System.Windows.Forms.BindingSource(this.components);
            // 
            // L_Note
            // 
            this.L_Note.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.sessionFormBindingSource1, "LastNote", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged, "C"));
            this.L_Note.Text = " ";
            // 
            // L_No
            // 
            this.L_No.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.sessionFormBindingSource2, "NoteIndex", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged, "1", "N0"));
            this.L_No.Text = " ";

【问题讨论】:

  • 您确认NotifyPropertyChanged 被解雇了吗?此外,虽然我感谢您尝试彻底,但在您的代码示例之上还有很多事情发生。如果您可以去除所有“噪音”并仅描述您在绑定时遇到的问题,您将更有可能获得帮助,即“标签L_NoteNo 绑定到NoteIndex,但它不会改变NoteIndex 的值发生变化。”
  • @DrewJordan:我做了检查,不,我没有开火,我不知道为什么,我缩短了 OP。我添加了额外的内容,以防我错过了一些你可以看到系统工作的东西,而不仅仅是问题。我本可以这样做,但你不会明白随之发生的其他事情可能会弄乱它。

标签: c# .net winforms binding inotifypropertychanged


【解决方案1】:

问题在于你调用NotifyPropertyChanged的方式:

NotifyPropertyChanged("note_index");

NotifyPropertyChanged("last_note");

只需从这样的调用中删除字符串

NotifyPropertyChanged();

一切都会好起来的。

编辑:如果不是,那么您的绑定没有正确初始化。证明:

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Forms;

namespace Tests
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new TestForm());
        }
    }
    class TestForm : Form, INotifyPropertyChanged
    {
        public TestForm()
        {
            var label = new Label { Parent = this, Left = 16, Top = 16, AutoSize = false, BorderStyle = BorderStyle.FixedSingle };
            label.DataBindings.Add("Text", this, "NoteIndex");
            var timer = new Timer { Interval = 200, Enabled = true };
            timer.Tick += (sender, e) => NoteIndex = (NoteIndex + 1) % 10;
        }
        int note_index;
        public int NoteIndex
        {
            get { return note_index; }
            private set
            {
                if (note_index != value)
                {
                    note_index = value;
                    NotifyPropertyChanged();
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

【讨论】:

  • 我先试过了……没用。潜在的修复是包含参数。
  • @SageKelly 不,这不是修复,而是错误。 NotifyPropertyChanged 应该使用 property 名称而不是 field 名称来调用。再试一次。如果它不起作用,请显示创建绑定的代码。
  • 我换成你说的,还是没有变化。请参阅 OP 进行更新。
  • @SageKelly 它开始变得无聊。除了答案中解决的错误之外,显然您的绑定和/或源未正确初始化。你看过我上面的例子吗——我正在绑定到表单实例——它实现了INotifyPropertyChanged 并包含数据。现在看看你的 - 你绑定到 2 个单独的 BindingSource 组件。 this.sessionFormBindingSource1.DataSource = thisthis.sessionFormBindingSource1.DataSource = this; 在哪里?您希望从这些空的绑定源中得到什么?如果不为空,代码在哪里?
  • 谢谢。我在发布“修复”/错误之前尝试过这个,但我不知道我应该使用“this”作为第二个参数。我使用的是 BindingSource 变量,就像 MSDN 网站告诉我的那样。你的解决方案奏效了。现在我要修复我的另一个变量。
猜你喜欢
  • 1970-01-01
  • 2016-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-27
  • 1970-01-01
  • 1970-01-01
  • 2016-11-07
相关资源
最近更新 更多