using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Reflection;
using System.Windows.Markup.Primitives;
using System.Diagnostics;
using System.Text.RegularExpressions;
namespace BindableConverterParameterTake2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
private void TextBox_Initialized(object item, EventArgs e)
{
}
private void Grid_Initialized(object sender, EventArgs e)
{
//get all dependency-objects in logical-tree
List<DependencyObject> AllLogicalTreeDependencyObjects=new List<DependencyObject>();
FillAllLogicalTreeDependencyObjects(ref AllLogicalTreeDependencyObjects,sender as DependencyObject );
//go over them
foreach (var item in AllLogicalTreeDependencyObjects)
{
MarkupObject markupObject = MarkupWriter.GetMarkupObjectFor(item);
IEnumerable<DependencyProperty> MatchingDPs = markupObject.Properties.Select<MarkupProperty, DependencyProperty>
(mp => { return mp.DependencyProperty; }).Where
(dp =>
{
return
dp != null &&
BindingOperations.GetBinding(item, dp) != null &&
BindingOperations.GetBinding(item, dp).ConverterParameter != null &&
Regex.IsMatch(BindingOperations.GetBinding(item, dp).ConverterParameter.ToString(), "Binding");
});
//for those who have Bindable converterParameter do the following:
foreach (DependencyProperty dp in MatchingDPs)
{
Match m = Regex.Match(BindingOperations.GetBinding(item, dp).ConverterParameter.ToString(), "Binding Path=(?<path>[A-Za-z0-9]+)");
if (m != null)
{
string sConverterParameterBindingPath = m.Groups["path"].Value;
// get original binding
Binding bindingOrig = BindingOperations.GetBinding(item, dp);
//create set of attached properties to replase this ConverterParameter Binding
//give unique name by using dp's name:
DependencyProperty apBindingSource=null;
//(5.) another attached prop for two-way binding operations
DependencyProperty apIsSourceChanged = DependencyProperty.RegisterAttached(dp.Name + "IsSourceChanged", typeof(bool), item.GetType(), new PropertyMetadata(false));
// 1. attached-prop for the ConverterParameter-Binding
DependencyProperty apConverterParameterBindingSource = DependencyProperty.RegisterAttached(dp.Name + "ConverterParameterBindingSource", typeof(object), item.GetType(), new PropertyMetadata(null));
Binding bindingConverterParameterBindingSource = new Binding(sConverterParameterBindingPath);
BindingOperations.SetBinding(item, apConverterParameterBindingSource, bindingConverterParameterBindingSource);
// 2. attached-prop to hold the Converter Object
DependencyProperty apConverter = DependencyProperty.RegisterAttached(dp.Name + "Converter", typeof(IValueConverter), item.GetType(), new PropertyMetadata(null));
(item).SetValue(apConverter, bindingOrig.Converter);
//3. attached-prop to hold the evaluate result >>> will be binded to the original Binded dp
DependencyProperty apEvaluatedResult = DependencyProperty.RegisterAttached(dp.Name + "EvaluatedResult", typeof(object), item.GetType(), new PropertyMetadata(null, (s, edp) =>
{
if (!(bool)s.GetValue(apIsSourceChanged))
{
// change didn't come from source>>> target got changed in two-way binding
// change source via convert back
object ret= (s.GetValue(apConverter) as IValueConverter).
ConvertBack(edp.NewValue, null, s.GetValue(apConverterParameterBindingSource), null);
s.SetValue(apBindingSource, ret);
}
}));
Binding bindingOrigDpToEvaluatedResult = new Binding("(" + item.GetType().Name + "." + dp.Name + "EvaluatedResult)");
bindingOrigDpToEvaluatedResult.Source = item;
bindingOrigDpToEvaluatedResult.Mode =bindingOrig.Mode;
BindingOperations.SetBinding(item, dp, bindingOrigDpToEvaluatedResult);
// 4. attached-prop to replace the source binding - bind apBindingSource to the original source (instead of the original dp)
apBindingSource = DependencyProperty.RegisterAttached(dp.Name + "BindingSource", typeof(object), item.GetType(), new PropertyMetadata(null, (s, edp) =>
{
s.SetValue(apIsSourceChanged, true);
s.SetValue(apEvaluatedResult, (s.GetValue(apConverter) as IValueConverter).
Convert(edp.NewValue, null, s.GetValue(apConverterParameterBindingSource), null));
s.SetValue(apIsSourceChanged, false);
}));
Binding NewBindingToSource = new Binding(bindingOrig.Path.Path);
NewBindingToSource.Mode =bindingOrig.Mode;
BindingOperations.SetBinding(item, apBindingSource, NewBindingToSource); // reroute source to apBindingSource
}
}
}
}
private void FillAllLogicalTreeDependencyObjects(ref List<DependencyObject> list, DependencyObject depobj)
{
List<DependencyObject> ret=new List<DependencyObject>();
list.Add(depobj);
var children = LogicalTreeHelper.GetChildren(depobj);
foreach (var item in children)
{
if (item is DependencyObject )
{
FillAllLogicalTreeDependencyObjects(ref list, item as DependencyObject );
}
}
}
}
}