如何设置从代码到可能尚不存在的列表成员的WPF绑定

本文关键字:不存在 列表 绑定 WPF 成员 何设置 设置 代码 | 更新日期: 2023-09-27 18:03:07

请允许我首先介绍一下我正在使用的类:

public class Assessment
{
    public List<NormDefinition> Definitions {get;set;}
    public List<Parameter> Parameters {get;set;}
}
public class NormDefinition
{
    public string ColumnName {get;set;}
}
public class Parameter
{
    public string Name {get;set;}
    public List<NormValue> Norms {get;set;}
}
public class NormValue
{
    public NormDefinition Definition {get;set;}
    public string Value {get;set;}
}

用户正在向导中导航,必须完成一些任务才能创建一个评估。

第一步是定义一个或多个normdefinition。它有比上面显示的更多的设置,但其他的与问题无关。

第二步是定义一个或多个parameter。但是,用户还可以为前面定义的NormDefinitions添加一些值。我试图通过创建一个具有ItemsSource ={绑定评估的DataGrid来做到这一点。,所以我知道每个绑定的源是绑定到该行的Parameter对象。

当第二个屏幕获得焦点时,一些代码为每个NormDefinition添加一列,用户可以在其中填写值。列的创建如下所示:

private void CreateNormDefinitionColumns()
{
    foreach (var definition in Assessment.Definitions)
    {
        DataGridTextColumn column = new DataGridTextColumn();
        column.Header = definition.ColumnName;
        column.Binding = new Binding()
        {
            // Add a binding to:
            // Parameter.Norms.Single(norm => norm.Definition == definition).Value;
        }
        ParameterDataGrid.Columns.Add(column);
    }
}

请给我一个解决方案来设置这个绑定。

更进一步,在. single()不返回结果的情况下,我希望创建NormValue对象并将其添加到参数中。

如何设置从代码到可能尚不存在的列表成员的WPF绑定

对于这种情况,我使用GenericRow和GenericTable类:

    public class GenericRow : CustomTypeDescriptor, INotifyPropertyChanged
    {
        #region Private Fields
        List<PropertyDescriptor> _property_list = new List<PropertyDescriptor>();
        #endregion
        #region INotifyPropertyChange Implementation
        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion INotifyPropertyChange Implementation
        #region Public Methods
        public void SetPropertyValue<T>(string propertyName, T propertyValue)
        {
            var properties = this.GetProperties()
                                    .Cast<PropertyDescriptor>()
                                    .Where(prop => prop.Name.Equals(propertyName));
            if (properties == null || properties.Count() != 1)
            {
                throw new Exception("The property doesn't exist.");
            }
            var property = properties.First();
            property.SetValue(this, propertyValue);
            OnPropertyChanged(propertyName);
        }
        public T GetPropertyValue<T>(string propertyName)
        {
            var properties = this.GetProperties()
                                .Cast<PropertyDescriptor>()
                                .Where(prop => prop.Name.Equals(propertyName));
            if (properties == null || properties.Count() != 1)
            {
                throw new Exception("The property doesn't exist.");
            }
            var property = properties.First();
            return (T)property.GetValue(this);
        }
        public void AddProperty<T, U>(string propertyName) where U : GenericRow
        {
            var customProperty =
                    new CustomPropertyDescriptor<T>(
                                            propertyName,
                                            typeof(U));
            _property_list.Add(customProperty);
        }
        #endregion
        #region Overriden Methods
        public override PropertyDescriptorCollection GetProperties()
        {
            var properties = base.GetProperties();
            return new PropertyDescriptorCollection(
                                properties.Cast<PropertyDescriptor>()
                                          .Concat(_property_list).ToArray());
        }
        #endregion



    }

:

 public class GenericTable
{
    private string tableName = "";
    public string TableName
    {
        get { return tableName; }
        set { tableName = value; }
    }
    private ObservableCollection<DataGridColumn> columnCollection;
    public ObservableCollection<DataGridColumn> ColumnCollection
    {
        get { return columnCollection; }
        private set { columnCollection = value; }
    }
    private ObservableCollection<GenericRow> genericRowCollection;
    public ObservableCollection<GenericRow> GenericRowCollection
    {
        get { return genericRowCollection; }
        set { genericRowCollection = value; }
    }


    public GenericTable(string tableName)
    {
        this.TableName = tableName;
        ColumnCollection = new ObservableCollection<DataGridColumn>();
        GenericRowCollection = new ObservableCollection<GenericRow>(); 
    }
    /// <summary>
    /// ColumnName is also binding property name
    /// </summary>
    /// <param name="columnName"></param>
    public void AddColumn(string columnName)
    {
        DataGridTextColumn column = new DataGridTextColumn();
        column.Header = columnName;
        column.Binding = new Binding(columnName);
        ColumnCollection.Add(column);
    }

    public override string ToString()
    {
        return TableName; 
    }

}

我认为你只需要这样修改你的Parameter类:

public class Parameter
{
    public string Name { get; set; }
    public List<NormValue> Norms { get; set; }
    public NormValue this[string columnName]
    {
        get
        {
            /* You can use Linq if you prefer */
            foreach (NormValue normValue in Norms)
            {
                if (StringComparer.OrdinalIgnoreCase.Compare(normValue.Definition.ColumnName, columnName) == 0)
                {
                    return normValue;
                }
            }
            NormValue newNormValue = new NormValue();
            newNormValue.Definition = new NormDefinition();
            newNormValue.Definition.ColumnName = columnName;
            newNormValue.Value = "Data is not available";
            Norms.Add(newNormValue);
            return newNormValue;
        }
    }
}

然后你可以这样构建DataGrid的列:

private void CreateNormDefinitionColumns()
{
    foreach (var definition in Assessment.Definitions)
    {
        Binding binding = new Binding(String.Format("[{0}].Value", definition.ColumnName));
        binding.Mode = BindingMode.TwoWay;
        DataGridTextColumn column = new DataGridTextColumn();
        column.Header = definition.ColumnName;
        column.Binding = binding;
        ParameterDataGrid.Columns.Add(column);
    }
}

当然你的类应该实现INotifyPropertyChanged,如果你想改变反映到UI。出于同样的原因,列表应该被ObservableCollections所取代。

相关文章: