简体   繁体   English

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

[英]WPF two way data bind to custom data type in observable collection

I'm trying to data bind to a custom data type property FormulaField in WPF. 我正在尝试将数据绑定到WPF中的自定义数据类型属性FormulaField I don't understand if there's something I've missed or if what I'm trying to do can't be done? 我不明白是否有什么我错过了或者我想做什么不能做?

I've followed the convention of how I've bound to a primitive and found that hasn't worked, there's not update on the FormulaField property. 我遵循了如何绑定到一个原语的约定,发现它没有工作, FormulaField属性没有更新。 I've also noticed that the custom data type set method is never hit. 我还注意到自定义数据类型集方法永远不会被命中。 I'm using MVVM. 我正在使用MVVM。

A model: 一个模型:

 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");
            }
        }
}

The NotificationObject implements INotifyPropertyChanged : 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 looks like this: FormulaField看起来像这样:

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

EDIT Implementing INotifyPropertyChanged in FormulaField goes stack overflow... 编辑在FormulaField实现INotifyPropertyChangedFormulaField堆栈溢出...

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));
            }
        }
    }

The Models sit inside an ObservableCollection in a ViewModel. 模型位于ViewModel中的ObservableCollection内。

An illustration of the View: 视图的说明:

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

Based upon what you wrote, you are raising INPC on "LiquidGOVLitres", which doesn't seem to appear in your code listing, but you are binding to "TOVLitres". 根据你所写的内容,你在“LiquidGOVLitres”上提出INPC,这似乎没有出现在你的代码清单中,但你绑定到“TOVLitres”。

Fixing this inconsistency will help, but you will also need to implement INPC on the FormulaField if you want changes to its members to be part of your UI. 修复此不一致性会有所帮助,但如果您希望更改其成员作为UI的一部分,则还需要在FormulaField上实现INPC。

ETA: After the clarifying edit to your code listing, the remaining task is to implement INPC on your FormulaField class and raise the event accordingly. ETA:在对代码清单进行澄清编辑之后,剩下的任务是在您的FormulaField类上实现INPC并相应地引发事件。

Also, if you are using 4.5 you can investigate the new Member Info class which helps avoid the use of magic strings in INPC. 此外,如果您使用的是4.5,则可以调查新的“成员信息”类,这有助于避免在INPC中使用魔术字符串。

Finally, for semantic clarity, it wouldn't hurt to rename "Value" to "FormulaValue"... 最后,为了语义清晰,将“Value”重命名为“FormulaValue”并不会有什么坏处......

To avoid recursion, try this model... 为避免递归,请尝试此模型...

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM