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

时间:2013-07-12 09:27:38

标签: c# wpf data-binding mvvm

我正在尝试将数据绑定到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如下所示:

public class FormulaField
{
    public bool UsesFormula { get; set; }
    public double Value { get; set; }
}

EDIT 在INotifyPropertyChanged中实现FormulaField会导致堆栈溢出...

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中的ObservableCollection内。

视图的说明:

<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>

1 个答案:

答案 0 :(得分:2)

根据你所写的内容,你在“LiquidGOVLitres”上提出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");
            }
        }
    }