I want to achieve that in a DataGrid a column displays TimeSpan
values as hh:mm
and users are only able to input values in such a format. I did this with a TextBox some time ago by implementing a user control encapsulating the TextBox and a IValueConverter
which takes care of value conversion.
However recently I read that user controls should be the last resort and there are easier ways like using attached properties. I found this approach for TextBoxes (/a/34085735/5772806) but I am unable to adapt it to DataGridColumns as the BindingExpression is not part of DataGridTextColumn but of its nested TextBox.
This is what I do have at the moment:
<code>public static class DataGridTimeColumnBehavior
public static readonly DependencyProperty IsTimeColumnProperty =
DependencyProperty.RegisterAttached(
typeof(DataGridTimeColumnBehavior),
new PropertyMetadata(false, OnIsTimeColumnChanged));
public static bool GetIsTimeColumn(DependencyObject obj)
return (bool)obj.GetValue(IsTimeColumnProperty);
public static void SetIsTimeColumn(DependencyObject obj, bool value)
obj.SetValue(IsTimeColumnProperty, value);
private static readonly DependencyProperty OriginalBindingExpressionProperty = DependencyProperty
"OriginalBindingExpression", typeof(BindingExpression), typeof(TextBoxExtensions),
new PropertyMetadata(default(BindingExpression)));
private static void SetOriginalBindingExpression(DependencyObject element, BindingExpression value)
element.SetValue(OriginalBindingExpressionProperty, value);
private static BindingExpression GetOriginalBindingExpression(DependencyObject element)
return (BindingExpression)element.GetValue(OriginalBindingExpressionProperty);
private static void OnIsTimeColumnChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
if (d is DataGridTextColumn column)
if (GetOriginalBindingExpression(column) == null)
// DataGridTextColumn does not contain a definition for GetBindingExpression
SetOriginalBindingExpression(column, column.GetBindingExpression(TextBox.TextProperty));
BindingExpression bindingExpression = GetOriginalBindingExpression(column);
Binding parentBinding = bindingExpression.ParentBinding;
Binding newBinding = new Binding(parentBinding.Path.Path)
ElementName = parentBinding.ElementName,
Path = parentBinding.Path,
Mode = parentBinding.Mode,
Converter = new TimeSpanStringConverter(),
UpdateSourceTrigger = parentBinding.UpdateSourceTrigger,
foreach (ValidationRule validationRule in parentBinding.ValidationRules)
newBinding.ValidationRules.Add(validationRule);
// DataGridTextColumn does not contain a definition for SetBinding
column.SetBinding(TextBox.TextProperty, newBinding);
<code>public static class DataGridTimeColumnBehavior
{
public static readonly DependencyProperty IsTimeColumnProperty =
DependencyProperty.RegisterAttached(
"IsTimeColumn",
typeof(bool),
typeof(DataGridTimeColumnBehavior),
new PropertyMetadata(false, OnIsTimeColumnChanged));
public static bool GetIsTimeColumn(DependencyObject obj)
{
return (bool)obj.GetValue(IsTimeColumnProperty);
}
public static void SetIsTimeColumn(DependencyObject obj, bool value)
{
obj.SetValue(IsTimeColumnProperty, value);
}
private static readonly DependencyProperty OriginalBindingExpressionProperty = DependencyProperty
.RegisterAttached(
"OriginalBindingExpression", typeof(BindingExpression), typeof(TextBoxExtensions),
new PropertyMetadata(default(BindingExpression)));
private static void SetOriginalBindingExpression(DependencyObject element, BindingExpression value)
{
element.SetValue(OriginalBindingExpressionProperty, value);
}
private static BindingExpression GetOriginalBindingExpression(DependencyObject element)
{
return (BindingExpression)element.GetValue(OriginalBindingExpressionProperty);
}
private static void OnIsTimeColumnChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is DataGridTextColumn column)
{
if (GetOriginalBindingExpression(column) == null)
{
// DataGridTextColumn does not contain a definition for GetBindingExpression
SetOriginalBindingExpression(column, column.GetBindingExpression(TextBox.TextProperty));
}
BindingExpression bindingExpression = GetOriginalBindingExpression(column);
Binding parentBinding = bindingExpression.ParentBinding;
Binding newBinding = new Binding(parentBinding.Path.Path)
{
ElementName = parentBinding.ElementName,
Path = parentBinding.Path,
Mode = parentBinding.Mode,
Converter = new TimeSpanStringConverter(),
UpdateSourceTrigger = parentBinding.UpdateSourceTrigger,
};
foreach (ValidationRule validationRule in parentBinding.ValidationRules)
{
newBinding.ValidationRules.Add(validationRule);
}
// DataGridTextColumn does not contain a definition for SetBinding
column.SetBinding(TextBox.TextProperty, newBinding);
}
}
}
</code>
public static class DataGridTimeColumnBehavior
{
public static readonly DependencyProperty IsTimeColumnProperty =
DependencyProperty.RegisterAttached(
"IsTimeColumn",
typeof(bool),
typeof(DataGridTimeColumnBehavior),
new PropertyMetadata(false, OnIsTimeColumnChanged));
public static bool GetIsTimeColumn(DependencyObject obj)
{
return (bool)obj.GetValue(IsTimeColumnProperty);
}
public static void SetIsTimeColumn(DependencyObject obj, bool value)
{
obj.SetValue(IsTimeColumnProperty, value);
}
private static readonly DependencyProperty OriginalBindingExpressionProperty = DependencyProperty
.RegisterAttached(
"OriginalBindingExpression", typeof(BindingExpression), typeof(TextBoxExtensions),
new PropertyMetadata(default(BindingExpression)));
private static void SetOriginalBindingExpression(DependencyObject element, BindingExpression value)
{
element.SetValue(OriginalBindingExpressionProperty, value);
}
private static BindingExpression GetOriginalBindingExpression(DependencyObject element)
{
return (BindingExpression)element.GetValue(OriginalBindingExpressionProperty);
}
private static void OnIsTimeColumnChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is DataGridTextColumn column)
{
if (GetOriginalBindingExpression(column) == null)
{
// DataGridTextColumn does not contain a definition for GetBindingExpression
SetOriginalBindingExpression(column, column.GetBindingExpression(TextBox.TextProperty));
}
BindingExpression bindingExpression = GetOriginalBindingExpression(column);
Binding parentBinding = bindingExpression.ParentBinding;
Binding newBinding = new Binding(parentBinding.Path.Path)
{
ElementName = parentBinding.ElementName,
Path = parentBinding.Path,
Mode = parentBinding.Mode,
Converter = new TimeSpanStringConverter(),
UpdateSourceTrigger = parentBinding.UpdateSourceTrigger,
};
foreach (ValidationRule validationRule in parentBinding.ValidationRules)
{
newBinding.ValidationRules.Add(validationRule);
}
// DataGridTextColumn does not contain a definition for SetBinding
column.SetBinding(TextBox.TextProperty, newBinding);
}
}
}