mirror of
https://github.com/holgerb83/ModernWpfPlayground.git
synced 2025-04-18 22:43:50 +02:00
Many new plays
This commit is contained in:
parent
ef501d30ae
commit
2467cad2a1
1163
Annotations.cs
Normal file
1163
Annotations.cs
Normal file
File diff suppressed because it is too large
Load Diff
12
App.xaml.cs
12
App.xaml.cs
@ -1,17 +1,9 @@
|
|||||||
using System;
|
namespace ModernWpfPlayground
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Configuration;
|
|
||||||
using System.Data;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
|
|
||||||
namespace ModernWpfPlayground
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for App.xaml
|
/// Interaction logic for App.xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class App : Application
|
public partial class App
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
36
BaseViewModel.cs
Normal file
36
BaseViewModel.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using ModernWpfPlayground.Annotations;
|
||||||
|
|
||||||
|
namespace ModernWpfPlayground
|
||||||
|
{
|
||||||
|
public abstract class BaseViewModel : INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, object> _valueDict = new Dictionary<string, object>();
|
||||||
|
|
||||||
|
protected bool SetProperty<T>(T value, [CallerMemberName] string propertyName = null)
|
||||||
|
{
|
||||||
|
if (_valueDict.TryGetValue(propertyName, out var obj) && Equals(value, obj)) return false;
|
||||||
|
|
||||||
|
_valueDict[propertyName] = value;
|
||||||
|
OnPropertyChanged(propertyName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected T GetProperty<T>(T defaultValue = default, [CallerMemberName] string propertyName = null)
|
||||||
|
{
|
||||||
|
return _valueDict.TryGetValue(propertyName, out var obj) ? (T) obj : defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
[NotifyPropertyChangedInvocator]
|
||||||
|
[PublicAPI]
|
||||||
|
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
17
ContentDialogExample.xaml
Normal file
17
ContentDialogExample.xaml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<ui:ContentDialog
|
||||||
|
x:Class="ModernWpfPlayground.ContentDialogExample"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||||
|
Title="Save your work?"
|
||||||
|
CloseButtonText="Cancel"
|
||||||
|
DefaultButton="Close"
|
||||||
|
IsShadowEnabled="True"
|
||||||
|
PrimaryButtonText="Yes"
|
||||||
|
SecondaryButtonText="No">
|
||||||
|
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||||
|
<!-- Content body -->
|
||||||
|
<TextBlock Text="Lorem ipsum dolor sit amet, adipisicing elit." TextWrapping="Wrap" />
|
||||||
|
<CheckBox Content="Upload your content to the cloud." />
|
||||||
|
</StackPanel>
|
||||||
|
</ui:ContentDialog>
|
12
ContentDialogExample.xaml.cs
Normal file
12
ContentDialogExample.xaml.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using ModernWpf.Controls;
|
||||||
|
|
||||||
|
namespace ModernWpfPlayground
|
||||||
|
{
|
||||||
|
public partial class ContentDialogExample : ContentDialog
|
||||||
|
{
|
||||||
|
public ContentDialogExample()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
x:Class="ModernWpfPlayground.MainWindow"
|
x:Class="ModernWpfPlayground.MainWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:controls="clr-namespace:LsBricks.Controls"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:ModernWpfPlayground"
|
xmlns:local="clr-namespace:ModernWpfPlayground"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
@ -12,7 +13,12 @@
|
|||||||
Height="600"
|
Height="600"
|
||||||
ui:TitleBar.ExtendViewIntoTitleBar="True"
|
ui:TitleBar.ExtendViewIntoTitleBar="True"
|
||||||
ui:WindowHelper.UseModernWindowStyle="True"
|
ui:WindowHelper.UseModernWindowStyle="True"
|
||||||
|
TextOptions.TextFormattingMode="Display"
|
||||||
|
UseLayoutRounding="True"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
<Window.DataContext>
|
||||||
|
<local:WindowViewModel />
|
||||||
|
</Window.DataContext>
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
<local:PixelsToGridLengthConverter x:Key="PixelsToGridLength" />
|
<local:PixelsToGridLengthConverter x:Key="PixelsToGridLength" />
|
||||||
</Window.Resources>
|
</Window.Resources>
|
||||||
@ -166,26 +172,51 @@
|
|||||||
<ColumnDefinition />
|
<ColumnDefinition />
|
||||||
<ColumnDefinition />
|
<ColumnDefinition />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<StackPanel
|
<ui:SimpleStackPanel
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="10"
|
Margin="5"
|
||||||
Orientation="Vertical">
|
Orientation="Vertical"
|
||||||
<StackPanel.Resources>
|
Spacing="5">
|
||||||
<Style BasedOn="{StaticResource {x:Type Button}}" TargetType="Button">
|
|
||||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
|
||||||
<Setter Property="Margin" Value="5" />
|
|
||||||
</Style>
|
|
||||||
</StackPanel.Resources>
|
|
||||||
<Button HorizontalAlignment="Stretch" Content="New" />
|
<Button HorizontalAlignment="Stretch" Content="New" />
|
||||||
<Button HorizontalAlignment="Stretch" Content="Open" />
|
<Button HorizontalAlignment="Stretch" Content="Open" />
|
||||||
<Separator />
|
<Separator />
|
||||||
<Button HorizontalAlignment="Stretch" Content="Open catalog" />
|
<Button HorizontalAlignment="Stretch" Content="Open catalog" />
|
||||||
</StackPanel>
|
</ui:SimpleStackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem Header="General" />
|
<TabItem Header="General">
|
||||||
|
<ui:SimpleStackPanel Margin="5" Spacing="10">
|
||||||
|
<controls:PropertyPresenter2
|
||||||
|
Command="{Binding ShowDialogCommand}"
|
||||||
|
Label="Hello"
|
||||||
|
Symbol="x³"
|
||||||
|
Value="World" />
|
||||||
|
<controls:PropertyPresenter2
|
||||||
|
Label="Hallo"
|
||||||
|
Symbol="x²"
|
||||||
|
Value="{Binding ValidationTest}" />
|
||||||
|
<controls:PropertyPresenter2 Label="Hello" Value="{Binding BooleanValue}" />
|
||||||
|
|
||||||
|
<controls:PropertyPresenter2 Label="Hello">
|
||||||
|
<Slider
|
||||||
|
AutoToolTipPlacement="TopLeft"
|
||||||
|
Interval="1"
|
||||||
|
IsSnapToTickEnabled="True"
|
||||||
|
Maximum="150"
|
||||||
|
Minimum="50"
|
||||||
|
TickFrequency="10"
|
||||||
|
TickPlacement="BottomRight"
|
||||||
|
Value="{Binding SliderTest}" />
|
||||||
|
</controls:PropertyPresenter2>
|
||||||
|
<ui:ProgressRing
|
||||||
|
Width="{Binding SliderTest}"
|
||||||
|
Height="{Binding SliderTest}"
|
||||||
|
IsActive="{Binding BooleanValue}"
|
||||||
|
Visibility="{Binding VisibilityEnumTest}" />
|
||||||
|
<controls:PropertyPresenter2 Label="Visi" Value="{Binding VisibilityEnumTest}" />
|
||||||
|
</ui:SimpleStackPanel>
|
||||||
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
</Grid>
|
</Grid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</Window>
|
</Window>
|
||||||
|
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ModernWpfUI" Version="0.8.0-preview.200206.2" />
|
<PackageReference Include="ModernWpfUI" Version="0.8.0" />
|
||||||
|
<PackageReference Include="System.Drawing.Common" Version="4.7.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
2
ModernWpfPlayground.sln.DotSettings
Normal file
2
ModernWpfPlayground.sln.DotSettings
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:Boolean x:Key="/Default/CodeInspection/CodeAnnotations/NamespacesWithAnnotations/=ModernWpfPlayground_002EAnnotations/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
41
PropertyPresenter2/EnumToKeyValueListConverter.cs
Normal file
41
PropertyPresenter2/EnumToKeyValueListConverter.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
namespace LsBricks.Controls
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts enums to a List with KeyValuePairs.
|
||||||
|
/// </summary>
|
||||||
|
public class EnumToKeyValueListConverter : IValueConverter
|
||||||
|
{
|
||||||
|
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (!(value is Enum)) return Binding.DoNothing;
|
||||||
|
return (from object enumValue in Enum.GetValues(value.GetType())
|
||||||
|
select new KeyValuePair<string, object>(GetDescription(enumValue), enumValue)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the content of a description attribute of an enum.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enumValue"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static string GetDescription(object enumValue)
|
||||||
|
{
|
||||||
|
var descriptionAttribute = enumValue.GetType()
|
||||||
|
.GetField(enumValue.ToString()).GetCustomAttributes(false)
|
||||||
|
.OfType<DescriptionAttribute>().FirstOrDefault();
|
||||||
|
|
||||||
|
return descriptionAttribute?.Description ?? enumValue.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return Binding.DoNothing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
43
PropertyPresenter2/MagicSymbolControl.cs
Normal file
43
PropertyPresenter2/MagicSymbolControl.cs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Markup;
|
||||||
|
|
||||||
|
namespace LsBricks.Controls
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for <see cref="MagicSymbolControl"/>
|
||||||
|
/// </summary>
|
||||||
|
[ContentProperty(nameof(Symbol))]
|
||||||
|
public class MagicSymbolControl : ContentControl
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Dependency property for <see cref="Symbol"/> property
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty SymbolProperty = DependencyProperty.Register(nameof(Symbol), typeof(object), typeof(MagicSymbolControl), new PropertyMetadata(default, PropertyChangedCallback));
|
||||||
|
|
||||||
|
private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (d is MagicSymbolControl magic)
|
||||||
|
{
|
||||||
|
magic.Content = MagicSymbolConverter.ConvertToFrameworkElement(e.NewValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Symbol to show
|
||||||
|
/// </summary>
|
||||||
|
public object Symbol
|
||||||
|
{
|
||||||
|
get => GetValue(SymbolProperty);
|
||||||
|
set => SetValue(SymbolProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of <see cref="MagicSymbolControl"/>
|
||||||
|
/// </summary>
|
||||||
|
public MagicSymbolControl()
|
||||||
|
{
|
||||||
|
Focusable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
144
PropertyPresenter2/MagicSymbolConverter.cs
Normal file
144
PropertyPresenter2/MagicSymbolConverter.cs
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
using LsBricks.ElementMVVM.Types;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace LsBricks.Controls
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Magically converts a text to
|
||||||
|
/// </summary>
|
||||||
|
[ValueConversion(typeof(string), typeof(FrameworkElement))]
|
||||||
|
public class MagicSymbolConverter : IValueConverter
|
||||||
|
{
|
||||||
|
private const string NoParseKeyword = "noParse:";
|
||||||
|
private const string PathKeyword = "path:";
|
||||||
|
private const string DynResKeyword = "dynRes:";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return ConvertToFrameworkElement(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert string to Framework element.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static object ConvertToFrameworkElement(object value)
|
||||||
|
{
|
||||||
|
var data = value as string;
|
||||||
|
if (string.IsNullOrWhiteSpace(data)) return value; //maybe not a string. eventually something else.
|
||||||
|
|
||||||
|
if (data.StartsWith(NoParseKeyword, StringComparison.Ordinal)) return data.Substring(NoParseKeyword.Length);
|
||||||
|
|
||||||
|
if (data.StartsWith(PathKeyword, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
var path = data.Substring(PathKeyword.Length);
|
||||||
|
var icon = ObjectImageConverter.GetIcon(Geometry.Parse(path), Brushes.Black);
|
||||||
|
return new Image
|
||||||
|
{
|
||||||
|
Source = icon,
|
||||||
|
HorizontalAlignment = HorizontalAlignment.Right,
|
||||||
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
|
Height = 16
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.StartsWith(DynResKeyword, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
var resourceKey = data.Substring(DynResKeyword.Length);
|
||||||
|
//get icon from resource dictionary
|
||||||
|
return new Image
|
||||||
|
{
|
||||||
|
Source = Application.Current.FindResource(resourceKey) as ImageSource,
|
||||||
|
HorizontalAlignment = HorizontalAlignment.Right,
|
||||||
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
|
Height = 16
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var textComponents = ParseText(data);
|
||||||
|
return CreateTextBlock(textComponents);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TextBlock CreateTextBlock(IEnumerable<TextComponent> textComponents)
|
||||||
|
{
|
||||||
|
//create text block
|
||||||
|
var block = new TextBlock();
|
||||||
|
foreach (var tc in textComponents)
|
||||||
|
{
|
||||||
|
var run = new Run(tc.Text) { FontFamily = new FontFamily("Palatino Linotype"), FontSize = 16 };
|
||||||
|
switch (tc.Style)
|
||||||
|
{
|
||||||
|
case BaselineAlignment.Subscript:
|
||||||
|
run.BaselineAlignment = BaselineAlignment.Subscript;
|
||||||
|
run.FontSize = 12;
|
||||||
|
break;
|
||||||
|
case BaselineAlignment.Superscript:
|
||||||
|
run.BaselineAlignment = BaselineAlignment.Superscript;
|
||||||
|
run.FontSize = 12;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
block.Inlines.Add(run);
|
||||||
|
}
|
||||||
|
block.HorizontalAlignment = HorizontalAlignment.Right;
|
||||||
|
block.VerticalAlignment = VerticalAlignment.Center;
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<TextComponent> ParseText(string data)
|
||||||
|
{
|
||||||
|
//parse text
|
||||||
|
var textComponents = new List<TextComponent>();
|
||||||
|
var alignment = BaselineAlignment.Baseline;
|
||||||
|
var snippet = new StringBuilder();
|
||||||
|
foreach (var c in data)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '~':
|
||||||
|
if (snippet.Length > 0)
|
||||||
|
{
|
||||||
|
var comp = new TextComponent(snippet.ToString(), alignment);
|
||||||
|
textComponents.Add(comp);
|
||||||
|
snippet.Clear();
|
||||||
|
}
|
||||||
|
alignment = alignment == BaselineAlignment.Subscript ? BaselineAlignment.Baseline : BaselineAlignment.Subscript;
|
||||||
|
break;
|
||||||
|
case '^':
|
||||||
|
if (snippet.Length > 0)
|
||||||
|
{
|
||||||
|
var comp = new TextComponent(snippet.ToString(), alignment);
|
||||||
|
textComponents.Add(comp);
|
||||||
|
snippet.Clear();
|
||||||
|
}
|
||||||
|
alignment = alignment == BaselineAlignment.Superscript ? BaselineAlignment.Baseline : BaselineAlignment.Superscript;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
snippet.Append(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (snippet.Length > 0)
|
||||||
|
{
|
||||||
|
var comp = new TextComponent(snippet.ToString(), alignment);
|
||||||
|
textComponents.Add(comp);
|
||||||
|
snippet.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return textComponents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
=> Binding.DoNothing;
|
||||||
|
}
|
||||||
|
}
|
39
PropertyPresenter2/PropertyDataTemplateSelector.cs
Normal file
39
PropertyPresenter2/PropertyDataTemplateSelector.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace LsBricks.Controls
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Selects the right template on base of value-type.
|
||||||
|
/// </summary>
|
||||||
|
public class PropertyDataTemplateSelector : DataTemplateSelector
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Default data template. (currently Textbox)
|
||||||
|
/// </summary>
|
||||||
|
public DataTemplate DefaultDataTemplate { private get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Data template for boolean. (currently Checkbox)
|
||||||
|
/// </summary>
|
||||||
|
public DataTemplate BooleanDataTemplate { private get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Data template for enums. (currently Combobox)
|
||||||
|
/// </summary>
|
||||||
|
public DataTemplate EnumComboBoxDataTemplate { private get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override DataTemplate SelectTemplate(object item, DependencyObject container)
|
||||||
|
{
|
||||||
|
return item switch
|
||||||
|
{
|
||||||
|
bool _ => BooleanDataTemplate,
|
||||||
|
Enum _ => EnumComboBoxDataTemplate,
|
||||||
|
UIElement _ => null,
|
||||||
|
_ => DefaultDataTemplate
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
207
PropertyPresenter2/PropertyPresenter2.xaml
Normal file
207
PropertyPresenter2/PropertyPresenter2.xaml
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
<ContentControl
|
||||||
|
x:Class="LsBricks.Controls.PropertyPresenter2"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:controls="clr-namespace:LsBricks.Controls"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
x:Name="LayoutRoot"
|
||||||
|
d:DesignHeight="300"
|
||||||
|
d:DesignWidth="300"
|
||||||
|
Focusable="False"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<Validation.ErrorTemplate>
|
||||||
|
<ControlTemplate />
|
||||||
|
</Validation.ErrorTemplate>
|
||||||
|
<ContentControl.Resources>
|
||||||
|
<DataTemplate x:Key="DefaultDataTemplate">
|
||||||
|
<Grid>
|
||||||
|
<controls:TextBoxEx
|
||||||
|
x:Name="InputTextBox"
|
||||||
|
Text="{Binding Value, ElementName=LayoutRoot}"
|
||||||
|
Validation.ErrorTemplate="{DynamicResource ValidationErrorTemplate}"
|
||||||
|
Validation.ValidationAdornerSiteFor="{Binding ElementName=LayoutRoot}">
|
||||||
|
<TextBox.Style>
|
||||||
|
<Style BasedOn="{StaticResource {x:Type TextBox}}" TargetType="{x:Type controls:TextBoxEx}">
|
||||||
|
<Setter Property="IsReadOnly" Value="True" />
|
||||||
|
<Setter Property="UpdateBindingOnEnter" Value="False" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<MultiDataTrigger>
|
||||||
|
<MultiDataTrigger.Conditions>
|
||||||
|
<Condition Binding="{Binding Command, ElementName=LayoutRoot}" Value="{x:Null}" />
|
||||||
|
<Condition Binding="{Binding IsReadOnly, ElementName=LayoutRoot}" Value="False" />
|
||||||
|
<Condition Binding="{Binding IsChecked, ElementName=LayoutRoot, TargetNullValue=True}" Value="True" />
|
||||||
|
</MultiDataTrigger.Conditions>
|
||||||
|
<Setter Property="IsReadOnly" Value="False" />
|
||||||
|
<Setter Property="UpdateBindingOnEnter" Value="True" />
|
||||||
|
</MultiDataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</TextBox.Style>
|
||||||
|
</controls:TextBoxEx>
|
||||||
|
<TextBlock
|
||||||
|
Margin="6,0,0,0"
|
||||||
|
Padding="2,2,2,2"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsHitTestVisible="False"
|
||||||
|
Text="{Binding Watermark, ElementName=LayoutRoot}">
|
||||||
|
<TextBlock.Style>
|
||||||
|
<Style TargetType="TextBlock">
|
||||||
|
<Setter Property="Visibility" Value="Collapsed" />
|
||||||
|
<Setter Property="Opacity" Value="0.6" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding Text, ElementName=InputTextBox}" Value="">
|
||||||
|
<Setter Property="Visibility" Value="Visible" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding IsFocused, ElementName=InputTextBox}" Value="True">
|
||||||
|
<Setter Property="Opacity" Value="0.3" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</TextBlock.Style>
|
||||||
|
</TextBlock>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
<DataTemplate x:Key="BooleanDataTemplate">
|
||||||
|
<CheckBox
|
||||||
|
Margin="0,4"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsChecked="{Binding Value, ElementName=LayoutRoot}"
|
||||||
|
Validation.ErrorTemplate="{DynamicResource ValidationErrorTemplate}"
|
||||||
|
Validation.ValidationAdornerSiteFor="{Binding ElementName=LayoutRoot}">
|
||||||
|
<CheckBox.Style>
|
||||||
|
<Style BasedOn="{StaticResource {x:Type CheckBox}}" TargetType="{x:Type CheckBox}">
|
||||||
|
<Setter Property="IsEnabled" Value="False" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<MultiDataTrigger>
|
||||||
|
<MultiDataTrigger.Conditions>
|
||||||
|
<Condition Binding="{Binding Command, ElementName=LayoutRoot}" Value="{x:Null}" />
|
||||||
|
<Condition Binding="{Binding IsReadOnly, ElementName=LayoutRoot}" Value="False" />
|
||||||
|
<Condition Binding="{Binding IsChecked, ElementName=LayoutRoot, TargetNullValue=True}" Value="True" />
|
||||||
|
</MultiDataTrigger.Conditions>
|
||||||
|
<Setter Property="IsEnabled" Value="True" />
|
||||||
|
</MultiDataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</CheckBox.Style>
|
||||||
|
</CheckBox>
|
||||||
|
</DataTemplate>
|
||||||
|
<controls:EnumToKeyValueListConverter x:Key="EnumToKeyValuePairConverter" />
|
||||||
|
<DataTemplate x:Key="EnumComboBoxDataTemplate">
|
||||||
|
<ComboBox
|
||||||
|
DisplayMemberPath="Key"
|
||||||
|
ItemsSource="{Binding Value, ElementName=LayoutRoot, Converter={StaticResource EnumToKeyValuePairConverter}}"
|
||||||
|
SelectedValue="{Binding Value, ElementName=LayoutRoot}"
|
||||||
|
SelectedValuePath="Value"
|
||||||
|
Validation.ErrorTemplate="{DynamicResource ValidationErrorTemplate}"
|
||||||
|
Validation.ValidationAdornerSiteFor="{Binding ElementName=LayoutRoot}">
|
||||||
|
<ComboBox.Style>
|
||||||
|
<Style BasedOn="{StaticResource {x:Type ComboBox}}" TargetType="{x:Type ComboBox}">
|
||||||
|
<Setter Property="IsEnabled" Value="False" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<MultiDataTrigger>
|
||||||
|
<MultiDataTrigger.Conditions>
|
||||||
|
<Condition Binding="{Binding Command, ElementName=LayoutRoot}" Value="{x:Null}" />
|
||||||
|
<Condition Binding="{Binding IsReadOnly, ElementName=LayoutRoot}" Value="False" />
|
||||||
|
<Condition Binding="{Binding IsChecked, ElementName=LayoutRoot, TargetNullValue=True}" Value="True" />
|
||||||
|
</MultiDataTrigger.Conditions>
|
||||||
|
<Setter Property="IsEnabled" Value="True" />
|
||||||
|
</MultiDataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</ComboBox.Style>
|
||||||
|
</ComboBox>
|
||||||
|
</DataTemplate>
|
||||||
|
<controls:PropertyDataTemplateSelector
|
||||||
|
x:Key="DataTemplateSelector"
|
||||||
|
BooleanDataTemplate="{StaticResource BooleanDataTemplate}"
|
||||||
|
DefaultDataTemplate="{StaticResource DefaultDataTemplate}"
|
||||||
|
EnumComboBoxDataTemplate="{StaticResource EnumComboBoxDataTemplate}" />
|
||||||
|
</ContentControl.Resources>
|
||||||
|
<Grid Margin="2">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="{Binding LabelWidth, ElementName=LayoutRoot, FallbackValue=150}" />
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid Grid.Column="0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<CheckBox
|
||||||
|
Grid.Column="0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsChecked="{Binding IsChecked, ElementName=LayoutRoot}">
|
||||||
|
<CheckBox.Style>
|
||||||
|
<Style BasedOn="{StaticResource {x:Type CheckBox}}" TargetType="CheckBox">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding IsChecked, ElementName=LayoutRoot}" Value="{x:Null}">
|
||||||
|
<Setter Property="Visibility" Value="Collapsed" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding IsReadOnly, ElementName=LayoutRoot}" Value="True">
|
||||||
|
<Setter Property="IsEnabled" Value="False" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</CheckBox.Style>
|
||||||
|
</CheckBox>
|
||||||
|
<TextBlock
|
||||||
|
x:Name="PartLabel"
|
||||||
|
Grid.Column="1"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Focusable="False"
|
||||||
|
Text="{Binding Label, ElementName=LayoutRoot}" />
|
||||||
|
<controls:MagicSymbolControl
|
||||||
|
x:Name="PartSymbol"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="5,0"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Symbol="{Binding Symbol, ElementName=LayoutRoot}" />
|
||||||
|
</Grid>
|
||||||
|
<DockPanel Grid.Column="1">
|
||||||
|
<Button
|
||||||
|
x:Name="PartButton"
|
||||||
|
Command="{Binding Command, ElementName=LayoutRoot}"
|
||||||
|
CommandParameter="{Binding CommandParameter, ElementName=LayoutRoot}"
|
||||||
|
Content="{Binding CommandContent, ElementName=LayoutRoot}"
|
||||||
|
DockPanel.Dock="{Binding ButtonAlignment, ElementName=LayoutRoot}">
|
||||||
|
<Button.Style>
|
||||||
|
<Style BasedOn="{StaticResource {x:Type Button}}" TargetType="Button">
|
||||||
|
<Setter Property="IsEnabled" Value="False" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding ButtonAlignment, ElementName=LayoutRoot}" Value="Right">
|
||||||
|
<Setter Property="Margin" Value="5,0,0,0" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding ButtonAlignment, ElementName=LayoutRoot}" Value="Bottom">
|
||||||
|
<Setter Property="Margin" Value="0,5,0,0" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding ButtonAlignment, ElementName=LayoutRoot}" Value="Left">
|
||||||
|
<Setter Property="Margin" Value="0,0,5,0" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding ButtonAlignment, ElementName=LayoutRoot}" Value="Top">
|
||||||
|
<Setter Property="Margin" Value="0,0,0,5" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding Command, ElementName=LayoutRoot}" Value="{x:Null}">
|
||||||
|
<Setter Property="Visibility" Value="Collapsed" />
|
||||||
|
</DataTrigger>
|
||||||
|
<MultiDataTrigger>
|
||||||
|
<MultiDataTrigger.Conditions>
|
||||||
|
<Condition Binding="{Binding IsReadOnly, ElementName=LayoutRoot}" Value="False" />
|
||||||
|
<Condition Binding="{Binding IsChecked, ElementName=LayoutRoot, TargetNullValue=True}" Value="True" />
|
||||||
|
</MultiDataTrigger.Conditions>
|
||||||
|
<Setter Property="IsEnabled" Value="True" />
|
||||||
|
</MultiDataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</Button.Style>
|
||||||
|
</Button>
|
||||||
|
<ContentPresenter
|
||||||
|
x:Name="PartContent"
|
||||||
|
Content="{Binding Value, ElementName=LayoutRoot}"
|
||||||
|
ContentTemplateSelector="{StaticResource DataTemplateSelector}"
|
||||||
|
Focusable="False" />
|
||||||
|
</DockPanel>
|
||||||
|
</Grid>
|
||||||
|
</ContentControl>
|
178
PropertyPresenter2/PropertyPresenter2.xaml.cs
Normal file
178
PropertyPresenter2/PropertyPresenter2.xaml.cs
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Markup;
|
||||||
|
|
||||||
|
namespace LsBricks.Controls
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="ContentControl" />
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for PropertyPresenter.xaml
|
||||||
|
/// </summary>
|
||||||
|
[ContentProperty(nameof(Value))]
|
||||||
|
public sealed partial class PropertyPresenter2
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Button alignment property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty ButtonAlignmentProperty = DependencyProperty.Register(nameof(ButtonAlignment), typeof(Dock), typeof(PropertyPresenter2), new PropertyMetadata(Dock.Right));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Content of the command property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty CommandContentProperty = DependencyProperty.Register(nameof(CommandContent), typeof(object), typeof(PropertyPresenter2), new PropertyMetadata("..."));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command Parameter property
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(nameof(CommandParameter), typeof(object), typeof(PropertyPresenter2), new PropertyMetadata(default(object)));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command property
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(nameof(Command), typeof(ICommand), typeof(PropertyPresenter2), new PropertyMetadata(default(ICommand)));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// is checked property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register(nameof(IsChecked), typeof(bool?), typeof(PropertyPresenter2), new FrameworkPropertyMetadata(default(bool?), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is readonly property
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register(nameof(IsReadOnly), typeof(bool), typeof(PropertyPresenter2), new PropertyMetadata(default(bool)));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Label property
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty LabelProperty = DependencyProperty.Register(nameof(Label), typeof(string), typeof(PropertyPresenter2), new PropertyMetadata(default(string)));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// label width property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty LabelWidthProperty = DependencyProperty.Register(nameof(LabelWidth), typeof(double), typeof(PropertyPresenter2), new PropertyMetadata(150.0));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Symbol Property
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty SymbolProperty = DependencyProperty.Register(nameof(Symbol), typeof(object), typeof(PropertyPresenter2), new PropertyMetadata(default(object)));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Value Property
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(nameof(Value), typeof(object), typeof(PropertyPresenter2), new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Watermark Property
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register(nameof(Watermark), typeof(string), typeof(PropertyPresenter2), new FrameworkPropertyMetadata(default(string)));
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public PropertyPresenter2()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Button alignment.
|
||||||
|
/// </summary>
|
||||||
|
public Dock ButtonAlignment
|
||||||
|
{
|
||||||
|
get => (Dock)GetValue(ButtonAlignmentProperty);
|
||||||
|
set => SetValue(ButtonAlignmentProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand Command
|
||||||
|
{
|
||||||
|
get => (ICommand)GetValue(CommandProperty);
|
||||||
|
set => SetValue(CommandProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command content.
|
||||||
|
/// </summary>
|
||||||
|
public object CommandContent
|
||||||
|
{
|
||||||
|
get => GetValue(CommandContentProperty);
|
||||||
|
set => SetValue(CommandContentProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command parameter.
|
||||||
|
/// </summary>
|
||||||
|
public object CommandParameter
|
||||||
|
{
|
||||||
|
get => GetValue(CommandParameterProperty);
|
||||||
|
set => SetValue(CommandParameterProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IsChecked.
|
||||||
|
/// </summary>
|
||||||
|
public bool? IsChecked
|
||||||
|
{
|
||||||
|
get => (bool?)GetValue(IsCheckedProperty);
|
||||||
|
set => SetValue(IsCheckedProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IsReadOnly
|
||||||
|
/// </summary>
|
||||||
|
public bool IsReadOnly
|
||||||
|
{
|
||||||
|
get => (bool)GetValue(IsReadOnlyProperty);
|
||||||
|
set => SetValue(IsReadOnlyProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Label.
|
||||||
|
/// </summary>
|
||||||
|
public string Label
|
||||||
|
{
|
||||||
|
get => (string)GetValue(LabelProperty);
|
||||||
|
set => SetValue(LabelProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Label width.
|
||||||
|
/// </summary>
|
||||||
|
public double LabelWidth
|
||||||
|
{
|
||||||
|
get => (double)GetValue(LabelWidthProperty);
|
||||||
|
set => SetValue(LabelWidthProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Symbol.
|
||||||
|
/// </summary>
|
||||||
|
public object Symbol
|
||||||
|
{
|
||||||
|
get => GetValue(SymbolProperty);
|
||||||
|
set => SetValue(SymbolProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Value.
|
||||||
|
/// </summary>
|
||||||
|
public object Value
|
||||||
|
{
|
||||||
|
get => GetValue(ValueProperty);
|
||||||
|
set => SetValue(ValueProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Watermark.
|
||||||
|
/// </summary>
|
||||||
|
public string Watermark
|
||||||
|
{
|
||||||
|
get => (string)GetValue(WatermarkProperty);
|
||||||
|
set => SetValue(WatermarkProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => Value != null ? base.ToString() + " " + Value : base.ToString();
|
||||||
|
}
|
||||||
|
}
|
165
PropertyPresenter2/TextBoxEx.cs
Normal file
165
PropertyPresenter2/TextBoxEx.cs
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace LsBricks.Controls
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a TextBox that can update the binding on enter.
|
||||||
|
/// </summary>
|
||||||
|
public class TextBoxEx : TextBox
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Identifies the <see cref="MoveFocusOnEnter"/> dependency property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty MoveFocusOnEnterProperty =
|
||||||
|
DependencyProperty.Register(
|
||||||
|
"MoveFocusOnEnter", typeof(bool), typeof(TextBoxEx), new UIPropertyMetadata(true));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Identifies the <see cref="UpdateBindingOnEnter"/> dependency property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty UpdateBindingOnEnterProperty =
|
||||||
|
DependencyProperty.Register(
|
||||||
|
"UpdateBindingOnEnter", typeof(bool), typeof(TextBoxEx), new UIPropertyMetadata(true));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Identifies the <see cref="ScrollToHomeOnFocus"/> dependency property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty ScrollToHomeOnFocusProperty =
|
||||||
|
DependencyProperty.Register("ScrollToHomeOnFocus", typeof(bool), typeof(TextBoxEx), new PropertyMetadata(true));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Identifies the <see cref="SelectAllOnFocus"/> dependency property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty SelectAllOnFocusProperty =
|
||||||
|
DependencyProperty.Register("SelectAllOnFocus", typeof(bool), typeof(TextBoxEx), new PropertyMetadata(true));
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:LsBricks.Controls.TextBoxEx" /> class.
|
||||||
|
/// </summary>
|
||||||
|
public TextBoxEx()
|
||||||
|
{
|
||||||
|
GotKeyboardFocus += HandleGotKeyboardFocus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether to select all on focus.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <c>true</c> if all should be selected; otherwise, <c>false</c>.
|
||||||
|
/// </value>
|
||||||
|
public bool SelectAllOnFocus
|
||||||
|
{
|
||||||
|
get => (bool)GetValue(SelectAllOnFocusProperty);
|
||||||
|
set => SetValue(SelectAllOnFocusProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether to scroll to home on focus.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <c>true</c> if scroll is enabled; otherwise, <c>false</c>.
|
||||||
|
/// </value>
|
||||||
|
public bool ScrollToHomeOnFocus
|
||||||
|
{
|
||||||
|
get => (bool)GetValue(ScrollToHomeOnFocusProperty);
|
||||||
|
set => SetValue(ScrollToHomeOnFocusProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether MoveFocusOnEnter.
|
||||||
|
/// </summary>
|
||||||
|
public bool MoveFocusOnEnter
|
||||||
|
{
|
||||||
|
get => (bool)GetValue(MoveFocusOnEnterProperty);
|
||||||
|
|
||||||
|
set => SetValue(MoveFocusOnEnterProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether UpdateBindingOnEnter.
|
||||||
|
/// </summary>
|
||||||
|
public bool UpdateBindingOnEnter
|
||||||
|
{
|
||||||
|
get => (bool)GetValue(UpdateBindingOnEnterProperty);
|
||||||
|
|
||||||
|
set => SetValue(UpdateBindingOnEnterProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void OnPreviewKeyDown(KeyEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnPreviewKeyDown(e);
|
||||||
|
switch (e.Key)
|
||||||
|
{
|
||||||
|
case Key.Enter:
|
||||||
|
if (!AcceptsReturn)
|
||||||
|
{
|
||||||
|
if (UpdateBindingOnEnter)
|
||||||
|
{
|
||||||
|
// get the binding to the Text property
|
||||||
|
var bindingExpression = GetBindingExpression(TextProperty);
|
||||||
|
// update the source (do not update the target)
|
||||||
|
bindingExpression?.UpdateSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MoveFocusOnEnter)
|
||||||
|
{
|
||||||
|
// Move focus to next element
|
||||||
|
// http://madprops.org/blog/enter-to-tab-in-wpf/
|
||||||
|
if (e.OriginalSource is UIElement uiElement)
|
||||||
|
{
|
||||||
|
var shift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
|
||||||
|
uiElement.MoveFocus(new TraversalRequest(shift ? FocusNavigationDirection.Previous : FocusNavigationDirection.Next));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Key.Escape:
|
||||||
|
Undo();
|
||||||
|
SelectAll();
|
||||||
|
e.Handled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnPreviewMouseLeftButtonDown(e);
|
||||||
|
|
||||||
|
if (!IsKeyboardFocusWithin)
|
||||||
|
{
|
||||||
|
SelectAll();
|
||||||
|
Focus();
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles the got keyboard focus event.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The sender.</param>
|
||||||
|
/// <param name="e">The <see cref="KeyboardFocusChangedEventArgs" /> instance containing the event data.</param>
|
||||||
|
private void HandleGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (SelectAllOnFocus)
|
||||||
|
{
|
||||||
|
SelectAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ScrollToHomeOnFocus)
|
||||||
|
{
|
||||||
|
ScrollToHome();
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
PropertyPresenter2/TextComponent.cs
Normal file
31
PropertyPresenter2/TextComponent.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace LsBricks.ElementMVVM.Types
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A component of the symbol
|
||||||
|
/// </summary>
|
||||||
|
public readonly struct TextComponent
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text"></param>
|
||||||
|
/// <param name="style"></param>
|
||||||
|
public TextComponent(string text, BaselineAlignment style = BaselineAlignment.Baseline)
|
||||||
|
{
|
||||||
|
Text = text;
|
||||||
|
Style = style;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Text of the symbol component
|
||||||
|
/// </summary>
|
||||||
|
public readonly string Text;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Style of the symbol component
|
||||||
|
/// </summary>
|
||||||
|
public readonly BaselineAlignment Style;
|
||||||
|
}
|
||||||
|
}
|
124
PropertyPresenter2/ValueConverter.cs
Normal file
124
PropertyPresenter2/ValueConverter.cs
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Net;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using Brush = System.Windows.Media.Brush;
|
||||||
|
using Brushes = System.Windows.Media.Brushes;
|
||||||
|
using FontFamily = System.Windows.Media.FontFamily;
|
||||||
|
using Point = System.Windows.Point;
|
||||||
|
|
||||||
|
namespace LsBricks.Controls
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Makes an Bitmap from every Imageformat.
|
||||||
|
/// </summary>
|
||||||
|
public class ObjectImageConverter : IValueConverter
|
||||||
|
{
|
||||||
|
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
const string dynResPrefix = "dynRes:";
|
||||||
|
if (value is Bitmap bitmap)
|
||||||
|
{
|
||||||
|
return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight(16, 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(value is string strValue)) return Binding.DoNothing;
|
||||||
|
if (strValue.StartsWith(dynResPrefix, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
var resource = Application.Current.TryFindResource(strValue.Replace(dynResPrefix, string.Empty));
|
||||||
|
return resource is ImageSource source ? source : Binding.DoNothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strValue.StartsWith("text:", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
var parts = strValue.Split(':');
|
||||||
|
return parts.Length == 3 ? DrawText(WebUtility.HtmlDecode(parts[2]), parts[1], Brushes.Black) : Binding.DoNothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetIcon(Geometry.Parse(strValue), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
|
||||||
|
Binding.DoNothing;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get icon a ImageSource from geometry.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="geometry">geometry</param>
|
||||||
|
/// <param name="brush">color of the icon</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static ImageSource GetIcon(Geometry geometry, Brush brush)
|
||||||
|
{
|
||||||
|
if (brush == null)
|
||||||
|
brush = Brushes.Black;
|
||||||
|
var drawing = new GeometryDrawing(brush, null, geometry);
|
||||||
|
return new DrawingImage(drawing);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Draw text as ImageSource from string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">the text</param>
|
||||||
|
/// <param name="strFontFamily">font of the string</param>
|
||||||
|
/// <param name="brush">color of the string</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static ImageSource DrawText(string text, string strFontFamily, Brush brush)
|
||||||
|
{
|
||||||
|
var fontFamily = new FontFamily(strFontFamily);
|
||||||
|
var formattedText = new FormattedText(text,
|
||||||
|
CultureInfo.GetCultureInfo("en-us"),
|
||||||
|
FlowDirection.LeftToRight,
|
||||||
|
new Typeface(
|
||||||
|
fontFamily,
|
||||||
|
FontStyles.Normal,
|
||||||
|
FontWeights.Normal,
|
||||||
|
FontStretches.Normal),
|
||||||
|
64, brush);
|
||||||
|
|
||||||
|
var geometry = formattedText.BuildGeometry(new Point(0, 0));
|
||||||
|
return GetIcon(geometry, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invert boolean converter
|
||||||
|
/// </summary>
|
||||||
|
[ValueConversion(typeof(bool), typeof(bool))]
|
||||||
|
public class InverseBooleanConverter : IValueConverter
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
|
||||||
|
value is bool b ? !b : throw new InvalidOperationException("The target must be a boolean");
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => Binding.DoNothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// negate double converter
|
||||||
|
/// </summary>
|
||||||
|
[ValueConversion(typeof(double), typeof(double))]
|
||||||
|
public class NegateDoubleConverter : IValueConverter
|
||||||
|
{
|
||||||
|
/// <summary>Converts a value. </summary>
|
||||||
|
/// <returns>A converted value. If the method returns null, the valid null value is used.</returns>
|
||||||
|
/// <param name="value">The value produced by the binding source.</param>
|
||||||
|
/// <param name="targetType">The type of the binding target property.</param>
|
||||||
|
/// <param name="parameter">The converter parameter to use.</param>
|
||||||
|
/// <param name="culture">The culture to use in the converter.</param>
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
|
||||||
|
value is double d ? -d : throw new ArgumentException(nameof(value) + " is not a doubles");
|
||||||
|
|
||||||
|
/// <summary>Converts a value. </summary>
|
||||||
|
/// <returns>A converted value. If the method returns null, the valid null value is used.</returns>
|
||||||
|
/// <param name="value">The value that is produced by the binding target.</param>
|
||||||
|
/// <param name="targetType">The type to convert to.</param>
|
||||||
|
/// <param name="parameter">The converter parameter to use.</param>
|
||||||
|
/// <param name="culture">The culture to use in the converter.</param>
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => Binding.DoNothing;
|
||||||
|
}
|
||||||
|
}
|
38
RelayCommand.cs
Normal file
38
RelayCommand.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace ModernWpfPlayground
|
||||||
|
{
|
||||||
|
public class RelayCommand : ICommand
|
||||||
|
{
|
||||||
|
private readonly Predicate<object> _canExecute;
|
||||||
|
private readonly Action<object> _execute;
|
||||||
|
|
||||||
|
public RelayCommand(Action<object> execute)
|
||||||
|
{
|
||||||
|
_execute = execute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
|
||||||
|
{
|
||||||
|
_canExecute = canExecute;
|
||||||
|
_execute = execute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler CanExecuteChanged
|
||||||
|
{
|
||||||
|
add => CommandManager.RequerySuggested += value;
|
||||||
|
remove => CommandManager.RequerySuggested -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanExecute(object parameter)
|
||||||
|
{
|
||||||
|
return _canExecute?.Invoke(parameter) ?? true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(object parameter)
|
||||||
|
{
|
||||||
|
_execute(parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
46
WindowViewModel.cs
Normal file
46
WindowViewModel.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace ModernWpfPlayground
|
||||||
|
{
|
||||||
|
public class WindowViewModel : BaseViewModel
|
||||||
|
{
|
||||||
|
public WindowViewModel()
|
||||||
|
{
|
||||||
|
ShowDialogCommand = new RelayCommand(async x => await ShowDialogAsync(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ShowDialogAsync(object obj)
|
||||||
|
{
|
||||||
|
var dialog = new ContentDialogExample();
|
||||||
|
await dialog.ShowAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool BooleanValue
|
||||||
|
{
|
||||||
|
get => GetProperty(true);
|
||||||
|
set => SetProperty(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Visibility VisibilityEnumTest
|
||||||
|
{
|
||||||
|
get => GetProperty<Visibility>();
|
||||||
|
set => SetProperty(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double SliderTest
|
||||||
|
{
|
||||||
|
get => GetProperty<double>(100);
|
||||||
|
set => SetProperty(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double ValidationTest
|
||||||
|
{
|
||||||
|
get => GetProperty<double>();
|
||||||
|
set => SetProperty(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICommand ShowDialogCommand { get; }
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user