C# WPF双向数据绑定到可观察集合中的自定义数据类型

C# WPF双向数据绑定到可观察集合中的自定义数据类型,c#,wpf,data-binding,mvvm,C#,Wpf,Data Binding,Mvvm,我正在尝试将数据绑定到WPF中的自定义数据类型属性FormulaField。我不明白我是否错过了什么,或者我想做的事情是否做不到 我遵循了我如何绑定到一个原语的惯例,发现它不起作用,FormulaField属性没有更新。我还注意到,自定义数据类型集方法从未被命中。我正在使用MVVM 模型: public class OBQModel : NotificationObject { private FormulaField _tovLitres; p

我正在尝试将数据绑定到WPF中的自定义数据类型属性
FormulaField
。我不明白我是否错过了什么,或者我想做的事情是否做不到

我遵循了我如何绑定到一个原语的惯例,发现它不起作用,
FormulaField
属性没有更新。我还注意到,自定义数据类型集方法从未被命中。我正在使用MVVM

模型:

 public class OBQModel : NotificationObject
    {    
        private FormulaField _tovLitres;
        public FormulaField TOVLitres
        {
            get
            {
                if (_tovLitres.UsesFormula)
                {
                    _tovLitres.Value = ConversionHelper.USBarrelsToLitres(_tovBarrels);
                }
                return _tovLitres;
            }
            set
            {
                _tovLitres = value;
                RaisePropertyChanged("TOVLitres");
            }
        }
}
NotificationObject
实现了
INotifyPropertyChanged

public abstract class NotificationObject : DependencyObject, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChanged<T>(Expression<Func<T>> action)
        {
            var propertyName = GetPropertyName(action);
            RaisePropertyChanged(propertyName);
        }

        private static string GetPropertyName<T>(Expression<Func<T>> action)
        {
            var expression = (MemberExpression)action.Body;
            var propertyName = expression.Member.Name;
            return propertyName;
        }

        protected internal void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
编辑 在
FormulaField
中实现
INotifyPropertyChanged
会导致堆栈溢出

public class FormulaField : INotifyPropertyChanged
    {
        public bool UsesFormula { get; set; }
        public double Value
        {
            get
            {
                return Value;
            }
            set
            {
                Value = value;
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        // Create the OnPropertyChanged method to raise the event 
        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }
模型位于ViewModel中的
可观察集合

视图的图示:

<StackPanel>
    <DataGrid ItemsSource="{Binding OBQModelCollection}">    
     <DataGrid.Columns>
      <DataGridTemplateColumn Header="new TOV (L)" Width="100">
       <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
         <TextBox BorderThickness="0" 
                  Text="{Binding TOVLitres.Value, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
        </DataTemplate>
       </DataGridTemplateColumn.CellTemplate>
      </DataGridTemplateColumn>
     </DataGrid.Columns>
    </DataGrid>
</StackPanel>

根据您所写的内容,您正在“liquidGovlls”上提高INPC,它似乎没有出现在您的代码列表中,但您绑定到了“TOVLitres”

修复这种不一致性会有所帮助,但如果希望对其成员的更改成为UI的一部分,还需要在FormulaField上实现INPC

ETA:在对代码列表进行了明确的编辑之后,剩下的任务是在FormulaField类上实现INPC并相应地引发事件

此外,如果您使用的是4.5,您可以研究新的成员信息类,这有助于避免在INPC中使用魔术字符串

最后,为了语义清晰,将“Value”重命名为“FormulaValue”并没有什么坏处

要避免递归,请尝试此模型

    private double _value;
    public double Value
    {
        [DebuggerStepThrough]
        get { return _value; }
        [DebuggerStepThrough]
        set
        {
            if (Math.Abs(value - _value) > Double.Epsilon)
            {
                _value = value;
                OnPropertyChanged("Value");
            }
        }
    }

我不确定,但我认为问题在于您将文本绑定到FormulaField类的属性,而该属性不发送RaisePropertyChanged事件。尝试将其添加到“值”属性设置器。@Superforce尝试将什么添加到“值”属性设置器?是的,“FormulaField”类中有一个名为“值”的属性,文本框文本绑定到该属性。我认为您必须编辑他的setter以应用新值并添加RaisePropertyChanged事件。就像你对TOVLitres对象所做的那样。当我这样做时,我会得到一个堆栈溢出异常…闻起来像循环依赖是的,该属性与此无关。我将编辑我的问题,所以我这样做并得到堆栈溢出是的,因为“Value”(语句“Value=Value”)的setter调用“Value”的setter,这是一个递归调用。考虑使用支持字段,最好是私有的。啊,这就是私人的东西,非常感谢!这起作用了,你帮我了解了发生了什么
    private double _value;
    public double Value
    {
        [DebuggerStepThrough]
        get { return _value; }
        [DebuggerStepThrough]
        set
        {
            if (Math.Abs(value - _value) > Double.Epsilon)
            {
                _value = value;
                OnPropertyChanged("Value");
            }
        }
    }