Skip to content

Commit c362e8f

Browse files
committed
Some import and updates from others projects and refactoring
1 parent 8caf161 commit c362e8f

File tree

6 files changed

+254
-7
lines changed

6 files changed

+254
-7
lines changed

RegexDialog/Behaviors/SimplePropertyBindingBehavior.cs

Lines changed: 106 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
1-
using System.Windows;
1+
using System;
2+
using System.Windows;
23
using System.Windows.Interactivity;
34

45
namespace RegexDialog.Behaviors
56
{
67
public class SimplePropertyBindingBehavior : Behavior<DependencyObject>
78
{
89
private readonly ExpressionEvaluator expressionEvaluator = new ExpressionEvaluator();
10+
private string oldEventName = string.Empty;
11+
private EventHandler<EventArgs> eventHandler;
12+
13+
public SimplePropertyBindingBehavior()
14+
{
15+
eventHandler = new EventHandler<EventArgs>(OnTriggerEvent);
16+
}
917

1018
public string PropertyName
1119
{
@@ -19,13 +27,44 @@ public string PropertyName
1927

2028
public object Value
2129
{
22-
get { return (object)GetValue(ValueProperty); }
30+
get { return GetValue(ValueProperty); }
2331
set { SetValue(ValueProperty, value); }
2432
}
2533

2634
// Using a DependencyProperty as the backing store for Value. This enables animation, styling, binding, etc...
2735
public static readonly DependencyProperty ValueProperty =
28-
DependencyProperty.Register("Value", typeof(object), typeof(SimplePropertyBindingBehavior), new PropertyMetadata(null, DependencyPropertyChanged));
36+
DependencyProperty.Register("Value", typeof(object), typeof(SimplePropertyBindingBehavior), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, DependencyPropertyChanged));
37+
38+
/// <summary>
39+
/// Set to false to disable the update of the view from the viewModel
40+
/// </summary>
41+
public bool UpdateViewFromViewModel
42+
{
43+
get { return (bool)GetValue(UpdateViewFromViewModelProperty); }
44+
set { SetValue(UpdateViewFromViewModelProperty, value); }
45+
}
46+
47+
// Using a DependencyProperty as the backing store for UpdateViewFromViewModel. This enables animation, styling, binding, etc...
48+
public static readonly DependencyProperty UpdateViewFromViewModelProperty =
49+
DependencyProperty.Register("UpdateViewFromViewModel", typeof(bool), typeof(SimplePropertyBindingBehavior), new PropertyMetadata(true));
50+
51+
public string PropertyChangedTriggerEventName
52+
{
53+
get { return (string)GetValue(PropertyChangedTriggerEventNameProperty); }
54+
set { SetValue(PropertyChangedTriggerEventNameProperty, value); }
55+
}
56+
57+
// Using a DependencyProperty as the backing store for PropertyChangedTriggerEventName. This enables animation, styling, binding, etc...
58+
public static readonly DependencyProperty PropertyChangedTriggerEventNameProperty =
59+
DependencyProperty.Register("PropertyChangedTriggerEventName", typeof(string), typeof(SimplePropertyBindingBehavior), new PropertyMetadata(string.Empty, PropertyChangedTriggerEventNameChanged));
60+
61+
private static void PropertyChangedTriggerEventNameChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
62+
{
63+
if (dependencyObject is SimplePropertyBindingBehavior simplePropertyBinding)
64+
{
65+
simplePropertyBinding.TriggerEventSubscribe();
66+
}
67+
}
2968

3069
private static void DependencyPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
3170
{
@@ -39,22 +78,83 @@ protected override void OnAttached()
3978
{
4079
base.OnAttached();
4180

81+
TriggerEventSubscribe();
4282
UpdateValue();
4383
}
4484

45-
private void UpdateValue()
85+
protected override void OnDetaching()
86+
{
87+
base.OnDetaching();
88+
89+
TriggerEventUnsubscribe();
90+
}
91+
92+
private void TriggerEventSubscribe()
93+
{
94+
if (AssociatedObject != null)
95+
{
96+
TriggerEventUnsubscribe();
97+
if (!PropertyChangedTriggerEventName.Equals(string.Empty))
98+
{
99+
oldEventName = PropertyChangedTriggerEventName;
100+
101+
//WeakEventManager<type Final De l'objet, EventArgs>.AddHandler(AssociatedObject, PropertyChangedTriggerEventName, OnTriggerEvent);
102+
typeof(WeakEventManager<,>)
103+
.MakeGenericType(AssociatedObject.GetType(), typeof(EventArgs))
104+
.GetMethod("AddHandler")
105+
.Invoke(null, new object[] { AssociatedObject, PropertyChangedTriggerEventName, eventHandler });
106+
}
107+
}
108+
}
109+
110+
private void TriggerEventUnsubscribe()
111+
{
112+
if (!oldEventName.Equals(string.Empty))
113+
{
114+
//WeakEventManager<type Final De l'objet, EventArgs>.RemoveHandler(AssociatedObject, PropertyChangedTriggerEventName, OnTriggerEvent);
115+
typeof(WeakEventManager<,>)
116+
.MakeGenericType(AssociatedObject.GetType(), typeof(EventArgs))
117+
.GetMethod("RemoveHandler")
118+
.Invoke(null, new object[] { AssociatedObject, oldEventName, eventHandler });
119+
}
120+
}
121+
122+
private void OnTriggerEvent(object source, EventArgs args)
46123
{
47124
if (!PropertyName.Equals(string.Empty))
48125
{
49126
try
50127
{
51128
expressionEvaluator.Variables["obj"] = AssociatedObject;
52-
expressionEvaluator.Variables["value"] = Value; ;
53129

54-
expressionEvaluator.Evaluate($"obj.{PropertyName} = value");
130+
object result = expressionEvaluator.Evaluate($"obj.{PropertyName}");
131+
132+
if (!result.Equals(Value))
133+
Value = result;
55134
}
56135
catch { }
57136
}
58137
}
138+
139+
private void UpdateValue()
140+
{
141+
if (UpdateViewFromViewModel && AssociatedObject != null && !PropertyName.Equals(string.Empty))
142+
{
143+
try
144+
{
145+
expressionEvaluator.Variables["obj"] = AssociatedObject;
146+
object result = expressionEvaluator.Evaluate($"obj.{PropertyName}");
147+
148+
if (!result.Equals(Value))
149+
{
150+
expressionEvaluator.Variables["value"] = Value;
151+
152+
expressionEvaluator.Evaluate($"obj.{PropertyName} = value");
153+
}
154+
}
155+
catch
156+
{ }
157+
}
158+
}
59159
}
60160
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Globalization;
4+
using System.Windows.Data;
5+
using System.Windows.Markup;
6+
7+
namespace RegexDialog.Converters
8+
{
9+
/// <summary>
10+
/// Converter that use a string mathematical or pseudo C# expression to make the conversion.
11+
/// Use <c>binding</c> to inject the binding value in the expression (example <c>Abs(binding) + 1</c>)
12+
/// </summary>
13+
[ContentProperty("Expression")]
14+
public class ExpressionEvalConverter : BaseConverter, IValueConverter
15+
{
16+
/// <summary>
17+
/// The expression to evaluate to make the conversion. Use <c>binding</c> to inject the binding value in the expression. By default just <c>binding</c>
18+
/// </summary>
19+
public string Expression { get; set; } = "binding";
20+
21+
/// <summary>
22+
/// The expression to evaluate to make the back conversion. Use <c>binding</c> to inject the binding value in the expression. By default just <c>binding</c>
23+
/// </summary>
24+
public string ExpressionForConvertBack { get; set; } = "binding";
25+
26+
/// <summary>
27+
/// If <c>true</c> evaluate a string binding as an expression, if false just inject the binding in the Expression, By default : <c>false</c>
28+
/// </summary>
29+
public bool EvaluateBindingAsAnExpression { get; set; } = false;
30+
31+
/// <summary>
32+
/// If <c>true</c> evaluate a string binding as an expression, if <c>false</c> just inject the binding in the ExpressionForConvertBack, By default : <c>false</c>
33+
/// </summary>
34+
public bool EvaluateBindingAsAnExpressionForConvertBack { get; set; } = false;
35+
36+
/// <summary>
37+
/// If <c>true</c> Evaluate function is callables in an expression. If <c>false</c> Evaluate is not callable.
38+
/// By default : false for security
39+
/// </summary>
40+
public bool IsEvaluateFunctionActivated { get; set; } = false;
41+
42+
/// <summary>
43+
/// If <c>true</c> throw up all evaluate exceptions, if <c>false</c> just return the exception message as a string, By default <c>false</c>
44+
/// </summary>
45+
public bool ThrowExceptions { get; set; } = false;
46+
47+
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
48+
{
49+
try
50+
{
51+
ExpressionEvaluator evaluator = new ExpressionEvaluator();
52+
53+
evaluator.Namespaces.NamespacesListForWPFConverters();
54+
55+
evaluator.OptionEvaluateFunctionActive = IsEvaluateFunctionActivated;
56+
57+
if (EvaluateBindingAsAnExpression)
58+
{
59+
evaluator.Variables["binding"] = evaluator.Evaluate(value.ToString());
60+
}
61+
else
62+
{
63+
evaluator.Variables["binding"] = value;
64+
}
65+
66+
return evaluator.Evaluate(Expression);
67+
}
68+
catch (Exception ex)
69+
{
70+
if (ThrowExceptions)
71+
{
72+
throw;
73+
}
74+
else
75+
{
76+
return ex.Message;
77+
}
78+
}
79+
}
80+
81+
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
82+
{
83+
try
84+
{
85+
ExpressionEvaluator evaluator = new ExpressionEvaluator();
86+
87+
evaluator.Namespaces.NamespacesListForWPFConverters();
88+
89+
evaluator.OptionEvaluateFunctionActive = IsEvaluateFunctionActivated;
90+
91+
if (EvaluateBindingAsAnExpressionForConvertBack)
92+
{
93+
evaluator.Variables["binding"] = evaluator.Evaluate(value.ToString());
94+
}
95+
else
96+
{
97+
evaluator.Variables["binding"] = value;
98+
}
99+
100+
return evaluator.Evaluate(ExpressionForConvertBack);
101+
}
102+
catch (Exception ex)
103+
{
104+
if (ThrowExceptions)
105+
{
106+
throw;
107+
}
108+
else
109+
{
110+
return ex.Message;
111+
}
112+
}
113+
}
114+
}
115+
}

RegexDialog/RegExToolDialog.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@
157157
/>
158158
</StackPanel>
159159
</Button>
160-
<Button x:Name="SelectAllButton" Click="SelectAllButton_Click" IsEnabled="{Binding TextSourceOn, Converter={converters:EnumBooleanConverter InverseBool=True}, ConverterParameter='Directory'}">
160+
<Button x:Name="SelectAllButton" Click="SelectAllButton_Click" IsEnabled="{Binding TextSourceOn, Converter={converters:ExpressionEvalConverter Expression='binding == RegexTextSource.CurrentTab || binding == RegexTextSource.CurrentSelection'}}">
161161
<StackPanel Orientation="Horizontal">
162162
<Image Source="{StaticResource SelectPicture}"
163163
Width="16"

RegexDialog/RegExToolDialog.xaml.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ public string ReplacePatternText
175175
/// </summary>
176176
public RegExToolDialog()
177177
{
178+
NamespacesForExpressionEvalConverters.NamespaceToAdd.Add("RegexDialog");
179+
178180
InitializeComponent();
179181

180182
Init();

RegexDialog/RegexDialog.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@
248248
<Compile Include="Converters\ChainingConverter.cs" />
249249
<Compile Include="Converters\CustomBoolToVisibilityConverter.cs" />
250250
<Compile Include="Converters\EnumBooleanConverter.cs" />
251+
<Compile Include="Converters\ExpressionEvalConverter.cs" />
251252
<Compile Include="Model\RegexFileResult.cs" />
252253
<Compile Include="RegexPatternIndenter.cs" />
253254
<Compile Include="Utils\Config.cs" />
@@ -256,6 +257,7 @@
256257
<Compile Include="Model\RegexGroupResult.cs" />
257258
<Compile Include="Utils\ExpressionEvaluator.cs" />
258259
<Compile Include="Utils\IniFile.cs" />
260+
<Compile Include="Utils\NamespacesForExpressionEvalConverters.cs" />
259261
<Compile Include="Utils\ObservableDictionary.cs" />
260262
<Compile Include="Utils\PathUtils.cs" />
261263
<Compile Include="Model\RegexLanguageElement.cs" />
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System.Collections.Generic;
2+
3+
namespace RegexDialog
4+
{
5+
/// <summary>
6+
/// Contains a list of namespaces to add to and to remove from the sub ExpressionEvaluator of ExpressionEvalConverters
7+
/// </summary>
8+
internal static class NamespacesForExpressionEvalConverters
9+
{
10+
public static List<string> NamespaceToAdd { get; } = new List<string>()
11+
{
12+
"System.Windows",
13+
"System.Windows.Controls",
14+
"System.Windows.Media",
15+
"System.Windows.Shapes",
16+
};
17+
public static List<string> NamespaceToRemove { get; } = new List<string>()
18+
{
19+
"System.IO",
20+
};
21+
22+
public static void NamespacesListForWPFConverters(this List<string> list)
23+
{
24+
list.RemoveAll(ns => NamespaceToRemove.Contains(ns));
25+
list.AddRange(NamespaceToAdd);
26+
}
27+
}
28+
}

0 commit comments

Comments
 (0)