A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

155 lines
5.6 KiB

// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using Avalonia.Data;
using Avalonia.Utilities;
using System;
using System.Reactive.Disposables;
using System.Reactive.Subjects;
using Avalonia.Reactive;
using System.Diagnostics;
using Avalonia.Controls.Utils;
using Avalonia.Markup.Xaml.MarkupExtensions;
namespace Avalonia.Controls
{
/// <summary>
/// Represents a <see cref="T:Avalonia.Controls.DataGrid" /> column that can
/// bind to a property in the grid's data source.
/// </summary>
public abstract class DataGridBoundColumn : DataGridColumn
{
private IBinding _binding;
/// <summary>
/// Gets or sets the binding that associates the column with a property in the data source.
/// </summary>
//TODO Binding
[AssignBinding]
public virtual IBinding Binding
{
get
{
return _binding;
}
set
{
if (_binding != value)
{
if (OwningGrid != null && !OwningGrid.CommitEdit(DataGridEditingUnit.Row, exitEditingMode: true))
{
// Edited value couldn't be committed, so we force a CancelEdit
OwningGrid.CancelEdit(DataGridEditingUnit.Row, raiseEvents: false);
}
_binding = value;
if (_binding != null)
{
if(_binding is BindingBase binding)
{
if (binding.Mode == BindingMode.OneWayToSource)
{
throw new InvalidOperationException("DataGridColumn doesn't support BindingMode.OneWayToSource. Use BindingMode.TwoWay instead.");
}
var path = (binding as Binding)?.Path ?? (binding as CompiledBindingExtension)?.Path.ToString();
if (!string.IsNullOrEmpty(path) && binding.Mode == BindingMode.Default)
{
binding.Mode = BindingMode.TwoWay;
}
if (binding.Converter == null && string.IsNullOrEmpty(binding.StringFormat))
{
binding.Converter = DataGridValueConverter.Instance;
}
}
// Apply the new Binding to existing rows in the DataGrid
if (OwningGrid != null)
{
OwningGrid.OnColumnBindingChanged(this);
}
}
RemoveEditingElement();
}
}
}
/// <summary>
/// The binding that will be used to get or set cell content for the clipboard.
/// If the base ClipboardContentBinding is not explicitly set, this will return the value of Binding.
/// </summary>
public override IBinding ClipboardContentBinding
{
get
{
return base.ClipboardContentBinding ?? Binding;
}
set
{
base.ClipboardContentBinding = value;
}
}
//TODO Rename
//TODO Validation
protected sealed override IControl GenerateEditingElement(DataGridCell cell, object dataItem, out ICellEditBinding editBinding)
{
IControl element = GenerateEditingElementDirect(cell, dataItem);
editBinding = null;
if (Binding != null)
{
editBinding = BindEditingElement(element, BindingTarget, Binding);
}
return element;
}
private static ICellEditBinding BindEditingElement(IAvaloniaObject target, AvaloniaProperty property, IBinding binding)
{
var result = binding.Initiate(target, property, enableDataValidation: true);
if (result != null)
{
if(result.Subject != null)
{
var bindingHelper = new CellEditBinding(result.Subject);
var instanceBinding = new InstancedBinding(bindingHelper.InternalSubject, result.Mode, result.Priority);
BindingOperations.Apply(target, property, instanceBinding, null);
return bindingHelper;
}
BindingOperations.Apply(target, property, result, null);
}
return null;
}
protected abstract IControl GenerateEditingElementDirect(DataGridCell cell, object dataItem);
protected AvaloniaProperty BindingTarget { get; set; }
internal void SetHeaderFromBinding()
{
if (OwningGrid != null && OwningGrid.DataConnection.DataType != null
&& Header == null && Binding != null && Binding is BindingBase binding)
{
var path = (binding as Binding)?.Path ?? (binding as CompiledBindingExtension)?.Path.ToString();
if (!string.IsNullOrWhiteSpace(path))
{
var header = OwningGrid.DataConnection.DataType.GetDisplayName(path);
if (header != null)
{
Header = header;
}
}
}
}
}
}