Skip to content

Commit 61dad35

Browse files
committed
Add VS Theming to Dataverse Solution Project Dialog
Added custom controls (Button, DialogButton, ListBox, RadioButton, TextBlock, TextBox) with dependency properties and style keys. Introduced style resource dictionaries and registered them in DefaultStyles.cs and ShellInternalStyles.cs. Added enums (ButtonKind with Pill, TextKind, Operation) and NumericComparisonConverter for XAML triggers. Enhanced Property helper for attached inherited properties. Refactored DataverseSolutionProjectDialog.xaml to use new controls and styles, improving layout and bindings. Updated XrmTools.csproj to include new files and resources, increased dialog minimum size, and commented out unused references.
1 parent a7c78de commit 61dad35

25 files changed

Lines changed: 1178 additions & 123 deletions
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
namespace XrmTools.Shell.Controls;
2+
3+
using System.Windows;
4+
using XrmTools.Shell.Styles;
5+
using XrmTools.Shell.Helpers;
6+
7+
public class Button : System.Windows.Controls.Button
8+
{
9+
public static readonly DependencyProperty CornerRadiusProperty = Property.Register<Button, CornerRadius>(nameof(CornerRadius));
10+
public static readonly DependencyProperty KindProperty = Property.Register<Button, ButtonKind>(nameof(Kind));
11+
12+
static Button()
13+
{
14+
DefaultStyleKeyProperty.OverrideMetadata(typeof(Button), new FrameworkPropertyMetadata(typeof(Button)));
15+
}
16+
17+
public CornerRadius CornerRadius
18+
{
19+
get => (CornerRadius)GetValue(CornerRadiusProperty);
20+
set => SetValue(CornerRadiusProperty, Boxes.Box(value));
21+
}
22+
23+
public ButtonKind Kind
24+
{
25+
get => (ButtonKind)GetValue(KindProperty);
26+
set => SetValue(KindProperty, Boxes.Box(value));
27+
}
28+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
namespace XrmTools.Shell.Controls;
2+
3+
using XrmTools.Shell.Helpers;
4+
using System.Windows;
5+
6+
public class DialogButton : Button
7+
{
8+
public static readonly double ControlMinWidth = 120.0;
9+
public static readonly DependencyProperty MessageButtonsProperty = Property.Register<DialogButton, MessageBoxButton>(nameof(MessageButtons));
10+
public static readonly DependencyProperty ResultKindProperty = Property.Register<DialogButton, MessageBoxResult>(nameof(ResultKind));
11+
12+
static DialogButton()
13+
{
14+
DefaultStyleKeyProperty.OverrideMetadata(typeof(DialogButton), new FrameworkPropertyMetadata(typeof(DialogButton)));
15+
}
16+
17+
public MessageBoxButton MessageButtons
18+
{
19+
get => (MessageBoxButton)GetValue(MessageButtonsProperty);
20+
set => SetValue(MessageButtonsProperty, Boxes.Box(value));
21+
}
22+
23+
public MessageBoxResult ResultKind
24+
{
25+
get => (MessageBoxResult)GetValue(ResultKindProperty);
26+
set => SetValue(ResultKindProperty, Boxes.Box(value));
27+
}
28+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace XrmTools.Shell.Controls;
2+
3+
using System.Windows;
4+
5+
public class ListBox : System.Windows.Controls.ListBox
6+
{
7+
static ListBox()
8+
{
9+
DefaultStyleKeyProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(typeof(ListBox)));
10+
}
11+
12+
protected override DependencyObject GetContainerForItemOverride()
13+
{
14+
return new ListBoxItem();
15+
}
16+
17+
protected override bool IsItemItsOwnContainerOverride(object item) => item is ListBoxItem;
18+
}
19+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
namespace XrmTools.Shell.Controls;
2+
3+
using XrmTools.Shell.Helpers;
4+
using System.Windows;
5+
using System.Windows.Input;
6+
7+
public class RadioButton : System.Windows.Controls.RadioButton
8+
{
9+
public static readonly DependencyProperty FocusOnlyOnAccessKeyProperty = Property.Register<RadioButton, bool>(nameof(FocusOnlyOnAccessKey));
10+
11+
static RadioButton()
12+
{
13+
DefaultStyleKeyProperty.OverrideMetadata(typeof(RadioButton), new FrameworkPropertyMetadata(typeof(RadioButton)));
14+
}
15+
16+
public bool FocusOnlyOnAccessKey
17+
{
18+
get => (bool)GetValue(FocusOnlyOnAccessKeyProperty);
19+
set => SetValue(FocusOnlyOnAccessKeyProperty, value);
20+
}
21+
22+
protected override void OnAccessKey(AccessKeyEventArgs e)
23+
{
24+
if (FocusOnlyOnAccessKey)
25+
Focus();
26+
else
27+
base.OnAccessKey(e);
28+
}
29+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
namespace XrmTools.Shell.Controls;
2+
3+
using XrmTools.Shell.Helpers;
4+
using XrmTools.Shell.Styles;
5+
using System.Windows;
6+
using System.Windows.Automation;
7+
using System.Windows.Automation.Peers;
8+
using System.Windows.Media;
9+
using System.Windows.Threading;
10+
11+
public class TextBlock : System.Windows.Controls.TextBlock
12+
{
13+
private bool hasDeferredLiveRegionChange;
14+
public static readonly DependencyProperty KindProperty = Property.Register<TextBlock, TextKind>(nameof(Kind));
15+
public static readonly DependencyProperty PreferredTextFormattingModeProperty = Property.RegisterAttachedInherited<TextBlock, TextFormattingMode?>(nameof(PreferredTextFormattingMode));
16+
17+
static TextBlock()
18+
{
19+
DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBlock), new FrameworkPropertyMetadata(typeof(TextBlock)));
20+
TextProperty.OverrideMetadata(typeof(TextBlock), new FrameworkPropertyMetadata(new PropertyChangedCallback(TextChanged)));
21+
}
22+
23+
public TextKind Kind
24+
{
25+
get => (TextKind)this.GetValue(KindProperty);
26+
set => SetValue(KindProperty, Boxes.Box(value));
27+
}
28+
29+
public TextFormattingMode? PreferredTextFormattingMode
30+
{
31+
get => GetPreferredTextFormattingMode(this);
32+
}
33+
34+
public static TextFormattingMode? GetPreferredTextFormattingMode(DependencyObject dependencyObject)
35+
{
36+
return (TextFormattingMode?)(dependencyObject?.GetValue(PreferredTextFormattingModeProperty) ?? (object)null);
37+
}
38+
39+
public static void SetPreferredTextFormattingMode(
40+
DependencyObject dependencyObject,
41+
TextFormattingMode? textFormattingMode)
42+
{
43+
dependencyObject?.SetValue(PreferredTextFormattingModeProperty, Boxes.Box(textFormattingMode));
44+
}
45+
46+
private static void TextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
47+
{
48+
TextBlock textBlock = d as TextBlock;
49+
if (textBlock == null)
50+
return;
51+
if (!textBlock.IsLoaded && !textBlock.hasDeferredLiveRegionChange)
52+
{
53+
textBlock.hasDeferredLiveRegionChange = true;
54+
textBlock.Dispatcher.BeginInvoke((() =>
55+
{
56+
TextChanged(textBlock, e);
57+
textBlock.hasDeferredLiveRegionChange = false;
58+
}), DispatcherPriority.Input);
59+
}
60+
else
61+
{
62+
if (AutomationProperties.GetLiveSetting(textBlock) == AutomationLiveSetting.Off || !AutomationPeer.ListenerExists(AutomationEvents.LiveRegionChanged) || string.IsNullOrWhiteSpace(e.NewValue?.ToString()))
63+
return;
64+
(UIElementAutomationPeer.FromElement(textBlock) ?? UIElementAutomationPeer.CreatePeerForElement(textBlock))?.RaiseAutomationEvent(AutomationEvents.LiveRegionChanged);
65+
}
66+
}
67+
}
68+
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
namespace XrmTools.Shell.Controls;
2+
3+
using System.Windows;
4+
using System.Windows.Controls;
5+
using System.Windows.Input;
6+
using XrmTools.Shell.Styles;
7+
using XrmTools.Shell.Helpers;
8+
9+
public class TextBox : System.Windows.Controls.TextBox
10+
{
11+
public static readonly double ToolTipOffset = 5.0;
12+
public static readonly double TypingIndicatorHeightRest = 1.0;
13+
public static readonly double TypingIndicatorHeightTyping = 2.0;
14+
public static readonly DependencyProperty CornerRadiusProperty = Property.Register<TextBox, CornerRadius>(nameof(CornerRadius));
15+
public static readonly DependencyProperty HintTextProperty = Property.Register<TextBox, string>(nameof(HintText));
16+
17+
static TextBox()
18+
{
19+
DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(typeof(TextBox)));
20+
}
21+
22+
public TextBox()
23+
{
24+
SetResourceReference(SelectionBrushProperty, ShellColors.AccentFillSelectedTextBackgroundBrushKey);
25+
}
26+
27+
public CornerRadius CornerRadius
28+
{
29+
get => (CornerRadius)GetValue(CornerRadiusProperty);
30+
set => SetValue(CornerRadiusProperty, Boxes.Box(value));
31+
}
32+
33+
public string HintText
34+
{
35+
get => (string)GetValue(HintTextProperty);
36+
set => SetValue(HintTextProperty, value);
37+
}
38+
39+
protected override void OnContextMenuOpening(ContextMenuEventArgs e)
40+
{
41+
if (ContextMenu != null)
42+
return;
43+
ContextMenu = CreateContextMenu();
44+
}
45+
46+
private void AddMenuItem(ContextMenu contextMenu, ICommand command, string header)
47+
{
48+
ItemCollection items = contextMenu.Items;
49+
MenuItem newItem = new MenuItem
50+
{
51+
Command = command,
52+
CommandTarget = this,
53+
Header = header
54+
};
55+
items.Add(newItem);
56+
}
57+
58+
private ContextMenu CreateContextMenu()
59+
{
60+
ContextMenu contextMenu = new ContextMenu();
61+
AddMenuItem(contextMenu, ApplicationCommands.Cut, "Cut");
62+
AddMenuItem(contextMenu, ApplicationCommands.Copy, "Copy");
63+
AddMenuItem(contextMenu, ApplicationCommands.Paste, "Paste");
64+
return contextMenu;
65+
}
66+
}

src/XrmTools/Shell/Conveters/Converters.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,27 @@
22

33
using Microsoft.VisualStudio.PlatformUI;
44
using XrmTools.Shell.Conveters;
5+
using XrmTools.Shell.Styles;
56

67
public static class Converters
78
{
9+
private static object isGreaterThanConverter;
10+
811
public static readonly object MultiplyConverter = new MultiplyingConverter();
912
public static readonly object BitmapScalingModeConverter = new BitmapScalingModeConverter();
1013
public static readonly object ClipConverter = new Styles.ClipConverter();
1114
public static readonly object ColorOpacityConverter = new ColorOpacityConverter();
15+
public static object IsGreaterThanConverter
16+
{
17+
get
18+
{
19+
if (isGreaterThanConverter != null)
20+
return isGreaterThanConverter;
21+
isGreaterThanConverter = new NumericComparisonConverter
22+
{
23+
Operation = Operation.IsGreaterThan
24+
}; ;
25+
return isGreaterThanConverter;
26+
}
27+
}
1228
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
namespace XrmTools.Shell.Conveters;
2+
3+
using System;
4+
using System.Globalization;
5+
using System.Windows.Data;
6+
using XrmTools.Shell.Styles;
7+
8+
internal class NumericComparisonConverter : IValueConverter, IMultiValueConverter
9+
{
10+
public Operation Operation { get; set; }
11+
12+
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
13+
{
14+
bool flag;
15+
switch (value)
16+
{
17+
case byte num1:
18+
flag = Compare(num1, System.Convert.ToByte(parameter));
19+
break;
20+
case double num2:
21+
flag = Compare(num2, System.Convert.ToDouble(parameter));
22+
break;
23+
case float num3:
24+
flag = Compare(num3, System.Convert.ToSingle(parameter));
25+
break;
26+
case int num4:
27+
flag = Compare(num4, System.Convert.ToInt32(parameter));
28+
break;
29+
case long num5:
30+
flag = Compare(num5, System.Convert.ToInt64(parameter));
31+
break;
32+
case sbyte num6:
33+
flag = Compare(num6, System.Convert.ToSByte(parameter));
34+
break;
35+
case short num7:
36+
flag = Compare(num7, System.Convert.ToInt16(parameter));
37+
break;
38+
case uint num8:
39+
flag = Compare(num8, System.Convert.ToUInt32(parameter));
40+
break;
41+
case ulong num9:
42+
flag = Compare(num9, System.Convert.ToUInt64(parameter));
43+
break;
44+
case ushort num10:
45+
flag = Compare(num10, System.Convert.ToUInt16(parameter));
46+
break;
47+
default:
48+
throw new NotSupportedException(value.GetType().ToString());
49+
}
50+
return flag;
51+
}
52+
53+
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
54+
{
55+
if (values.Length != 2)
56+
throw new ArgumentException(nameof(values));
57+
return Convert(values[0], targetType, values[1], culture);
58+
}
59+
60+
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
61+
{
62+
throw new NotImplementedException();
63+
}
64+
65+
public object[] ConvertBack(
66+
object value,
67+
Type[] targetTypes,
68+
object parameter,
69+
CultureInfo culture)
70+
{
71+
throw new NotImplementedException();
72+
}
73+
74+
private bool Compare<T>(T value, T compareValue) where T : IComparable<T>
75+
{
76+
switch (Operation)
77+
{
78+
case Operation.IsEqual:
79+
return value.CompareTo(compareValue) == 0;
80+
case Operation.IsNotEqual:
81+
return value.CompareTo(compareValue) != 0;
82+
case Operation.IsGreaterThan:
83+
return value.CompareTo(compareValue) > 0;
84+
case Operation.IsGreaterThanOrEqual:
85+
return value.CompareTo(compareValue) >= 0;
86+
case Operation.IsLessThan:
87+
return value.CompareTo(compareValue) < 0;
88+
case Operation.IsLessThanOrEqual:
89+
return value.CompareTo(compareValue) <= 0;
90+
default:
91+
throw new NotSupportedException(Operation.ToString());
92+
}
93+
}
94+
}

0 commit comments

Comments
 (0)