Reorganization of files

This commit is contained in:
2020-04-21 20:52:55 +02:00
parent 441d1d2010
commit a21110fba9
28 changed files with 79 additions and 48 deletions

16
App/App.xaml Normal file
View File

@ -0,0 +1,16 @@
<dryIoc:PrismApplication
x:Class="ModernWpfPlayground.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dryIoc="http://prismlibrary.com/"
xmlns:ui="http://schemas.modernwpf.com/2019">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ui:ThemeResources />
<ui:IntellisenseResources Source="/ModernWpf;component/DesignTime/DesignTimeResources.xaml" />
<ui:XamlControlsResources />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</dryIoc:PrismApplication>

22
App/App.xaml.cs Normal file
View File

@ -0,0 +1,22 @@
using System.Windows;
using Prism.Ioc;
namespace ModernWpfPlayground
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App
{
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.Register<MainWindow>();
containerRegistry.Register<MainWindowViewModel>();
}
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
}
}

10
App/AssemblyInfo.cs Normal file
View File

@ -0,0 +1,10 @@
using System.Windows;
[assembly:ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

View File

@ -0,0 +1,21 @@
<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"
x:Name="LayoutRoot"
Title="Delete your work?"
CloseButtonText="Cancel"
DefaultButton="Close"
IsShadowEnabled="True"
PrimaryButtonText="Yes"
SecondaryButtonText="No">
<ui:SimpleStackPanel
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Spacing="10">
<!-- Content body -->
<TextBlock Text="Delete message?" />
<TextBlock TextWrapping="Wrap"><Run Text="&quot;" /><Run Text="{Binding Message, ElementName=LayoutRoot}" /><Run Text="&quot;" /></TextBlock>
</ui:SimpleStackPanel>
</ui:ContentDialog>

View File

@ -0,0 +1,21 @@
using System.Windows;
namespace ModernWpfPlayground
{
public partial class ContentDialogExample
{
public static readonly DependencyProperty MessageProperty = DependencyProperty.Register(
"Message", typeof(string), typeof(ContentDialogExample), new PropertyMetadata(default(string)));
public string Message
{
get => (string) GetValue(MessageProperty);
set => SetValue(MessageProperty, value);
}
public ContentDialogExample()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,7 @@
namespace ModernWpfPlayground
{
public class IntellisenseResourceDictionary : ModernWpf.DesignTime.IntellisenseResourcesBase
{
}
}

277
App/MainWindow.xaml Normal file
View File

@ -0,0 +1,277 @@
<Window
x:Class="ModernWpfPlayground.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="http://wpflib.de/"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ModernWpfPlayground"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:prism="http://prismlibrary.com/"
xmlns:ui="http://schemas.modernwpf.com/2019"
x:Name="Window"
Title="{Binding Title}"
Width="{Binding WindowWidth, Mode=TwoWay}"
Height="{Binding WindowHeight, Mode=TwoWay}"
d:DataContext="{d:DesignInstance local:MainWindowViewModel}"
prism:ViewModelLocator.AutoWireViewModel="True"
ui:ThemeManager.IsThemeAware="True"
ui:TitleBar.ExtendViewIntoTitleBar="True"
ui:WindowHelper.UseModernWindowStyle="True"
TextOptions.TextFormattingMode="Display"
UseLayoutRounding="True"
mc:Ignorable="d">
<Window.Resources>
<local:PixelsToGridLengthConverter x:Key="PixelsToGridLength" />
</Window.Resources>
<Window.InputBindings>
<KeyBinding
Key="O"
Command="{Binding OpenViewModelCommand}"
Modifiers="Control" />
<KeyBinding
Key="S"
Command="{Binding SaveViewModelCommand}"
Modifiers="Control" />
<KeyBinding
Key="N"
Command="{Binding ResetViewModelCommand}"
Modifiers="Control" />
</Window.InputBindings>
<DockPanel>
<!-- TitleBar -->
<Grid
Height="{Binding ElementName=Window, Path=(ui:TitleBar.Height)}"
Background="{DynamicResource SystemControlBackgroundChromeMediumBrush}"
DockPanel.Dock="Top">
<Grid.Style>
<Style TargetType="Grid">
<Setter Property="TextElement.Foreground" Value="{DynamicResource SystemControlForegroundBaseHighBrush}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsActive, ElementName=Window}" Value="False">
<Setter Property="TextElement.Foreground" Value="{DynamicResource SystemControlDisabledBaseMediumLowBrush}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding ElementName=Window, Path=(ui:TitleBar.SystemOverlayLeftInset), Converter={StaticResource PixelsToGridLength}}" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Menu
Grid.Column="1"
Height="{Binding ElementName=Window, Path=(ui:TitleBar.Height)}"
Margin="0"
Padding="0"
WindowChrome.IsHitTestVisibleInChrome="True">
<Menu.Resources>
<Style BasedOn="{StaticResource {x:Type MenuItem}}" TargetType="MenuItem">
<Style.Triggers>
<Trigger Property="Role" Value="TopLevelHeader">
<Setter Property="Height" Value="{Binding ElementName=Window, Path=(ui:TitleBar.Height)}" />
</Trigger>
<DataTrigger Binding="{Binding IsActive, ElementName=Window}" Value="False">
<Setter Property="TextElement.Foreground" Value="{DynamicResource SystemControlDisabledBaseMediumLowBrush}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Menu.Resources>
<MenuItem Header="File">
<MenuItem
Command="{Binding ResetViewModelCommand}"
Header="New"
InputGestureText="Ctrl+N" />
<MenuItem
Command="{Binding OpenViewModelCommand}"
Header="Open"
InputGestureText="Ctrl+O" />
<MenuItem
Command="{Binding SaveViewModelCommand}"
Header="Save"
InputGestureText="Ctrl+S" />
<Separator />
<MenuItem
Command="{Binding CloseCommand}"
Header="Close"
InputGestureText="Alt+F4" />
</MenuItem>
<MenuItem Header="Edit">
<MenuItem Header="Copy" />
<MenuItem Header="Cut" />
<MenuItem Header="Paste" />
</MenuItem>
<MenuItem Header="Help">
<MenuItem Header="?" />
<Separator />
<MenuItem Header="Info" />
</MenuItem>
</Menu>
<!-- Horizontally centered title -->
<TextBlock
Grid.Column="0"
Grid.ColumnSpan="4"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="13"
Text="{Binding ElementName=Window, Path=Title}" />
<ui:PersonPicture
Grid.Column="3"
Height="24"
Margin="0,0,150,0"
DisplayName="Holger Börchers"
ToolTip="Holger Börchers"
WindowChrome.IsHitTestVisibleInChrome="True" />
</Grid>
<!-- Footer -->
<Grid
Height="24"
Background="#00564C"
DockPanel.Dock="Bottom">
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="White" />
<Setter Property="Margin" Value="10,0" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Holger Börchers" />
<TextBlock Grid.Column="1" Text="|" />
<TextBlock Grid.Column="2" Text="SQL-SRV\SQLEXPRESS" />
<TextBlock
Grid.Column="3"
HorizontalAlignment="Right"
Text="BlaBlaBla" />
</Grid>
<!-- Content -->
<Grid Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border
Grid.Column="0"
Panel.ZIndex="1"
Background="#2C2C2C"
BorderThickness="0">
<ui:SimpleStackPanel HorizontalAlignment="Center" Spacing="10">
<ui:SimpleStackPanel.Resources>
<Style TargetType="TextBlock">
<Setter Property="LayoutTransform">
<Setter.Value>
<RotateTransform Angle="-90" />
</Setter.Value>
</Setter>
</Style>
<Style TargetType="ui:ToggleSwitch">
<Setter Property="LayoutTransform">
<Setter.Value>
<RotateTransform Angle="-90" />
</Setter.Value>
</Setter>
</Style>
</ui:SimpleStackPanel.Resources>
<ui:ToggleSwitch
Margin="0,5,0,0"
IsOn="{Binding IsPaneOpen}"
ToolTip="Show/hide element tree" />
<TextBlock
Cursor="Hand"
FontSize="20"
Foreground="#F4F4F4"
Text="Dummy active" />
<TextBlock
Cursor="Hand"
FontSize="20"
Foreground="#808080"
Text="Dummy inactive" />
</ui:SimpleStackPanel>
</Border>
<ui:SplitView
Grid.Column="1"
Panel.ZIndex="0"
BorderThickness="0"
DisplayMode="Inline"
IsPaneOpen="{Binding IsPaneOpen}"
PanePlacement="Left">
<ui:SplitView.Pane>
<TreeViewItem Header="Root" IsExpanded="True">
<TreeViewItem Header="Child1" />
<TreeViewItem Header="Child2" />
<TreeViewItem Header="Child3" />
</TreeViewItem>
</ui:SplitView.Pane>
<TabControl>
<TabItem Header="Bolt">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ui:SimpleStackPanel
Grid.Column="0"
Margin="5"
Orientation="Vertical"
Spacing="5">
<Button
HorizontalAlignment="Stretch"
Command="{Binding OpenViewModelCommand}"
Content="Open" />
<Button
HorizontalAlignment="Stretch"
Command="{Binding SaveViewModelCommand}"
Content="Save" />
</ui:SimpleStackPanel>
</Grid>
</TabItem>
<TabItem Header="General" IsSelected="True">
<ui:SimpleStackPanel Margin="5" Spacing="10">
<controls:PropertyPresenter Label="Theme Mode" Value="{Binding ThemeMode}" />
<controls:PropertyPresenter
Command="{Binding ShowDialogCommand}"
Label="Hello"
Symbol="x³"
Value="{Binding WelcomeMessage}" />
<controls:PropertyPresenter
IsReadOnly="True"
Label="Hallo"
Symbol="x²"
Value="{Binding ValidationTest, UpdateSourceTrigger=PropertyChanged}" />
<controls:PropertyPresenter
Label="Good bye"
Symbol="x²"
Value="{Binding ValidationTest, UpdateSourceTrigger=PropertyChanged}" />
<controls:PropertyPresenter Label="Hello" Value="{Binding BooleanValue}" />
<controls:PropertyPresenter Label="Hello">
<Slider
AutoToolTipPlacement="TopLeft"
Interval="1"
IsSnapToTickEnabled="True"
Maximum="150"
Minimum="50"
TickFrequency="10"
TickPlacement="BottomRight"
Value="{Binding SliderTest}" />
</controls:PropertyPresenter>
<ui:ProgressRing
Width="{Binding SliderTest}"
Height="{Binding SliderTest}"
IsActive="{Binding BooleanValue}"
Visibility="{Binding VisibilityEnumTest}" />
<controls:PropertyPresenter Label="Visi" Value="{Binding VisibilityEnumTest}" />
</ui:SimpleStackPanel>
</TabItem>
</TabControl>
</ui:SplitView>
</Grid>
</DockPanel>
</Window>

13
App/MainWindow.xaml.cs Normal file
View File

@ -0,0 +1,13 @@
namespace ModernWpfPlayground
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
}
}

167
App/MainWindowViewModel.cs Normal file
View File

@ -0,0 +1,167 @@
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using Microsoft.Win32;
using ModernWpf;
using ModernWpfPlayground.MvvmStuff;
using Prism.Commands;
using YamlDotNet.Serialization;
namespace ModernWpfPlayground
{
public class MainWindowViewModel : BaseViewModel
{
private const string AppName = "TaBEA 3.0.0";
private string? _path;
private string _title = AppName;
private readonly ISerializer _serializer;
private readonly IDeserializer _deserializer;
private bool _isPaneOpen = true;
public MainWindowViewModel()
{
ShowDialogCommand = new DelegateCommand(async () => await ShowDialogAsync().ConfigureAwait(false));
CloseCommand = new DelegateCommand(() => Application.Current.Shutdown());
OpenViewModelCommand = new DelegateCommand(LoadViewModel);
SaveViewModelCommand = new DelegateCommand(SaveViewModel);
ResetViewModelCommand = new DelegateCommand(() =>
{
ResetViewModel();
Path = null;
});
_serializer = new SerializerBuilder().Build();
_deserializer = new DeserializerBuilder().Build();
}
public string? Path
{
get => _path;
private set => SetProperty(ref _path, value,
() => Title = value != null ? $"{System.IO.Path.GetFileName(value)} - {AppName}" : AppName);
}
public string Title
{
get => _title;
set => SetProperty(ref _title, value);
}
public bool BooleanValue
{
get => GetProperty(true);
set => SetProperty(value, BooleanValue_OnChanged);
}
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; }
public string WelcomeMessage
{
get => GetProperty("Shadow of the empire");
set => SetProperty(value);
}
public ICommand CloseCommand { get; }
public ICommand OpenViewModelCommand { get; }
public ICommand SaveViewModelCommand { get; }
public ICommand ResetViewModelCommand { get; }
public ThemeMode ThemeMode
{
get => GetProperty(ThemeMode.UseSystemSetting);
set => SetProperty(value, SetTheme);
}
public int WindowWidth
{
get => GetProperty(1200);
set => SetProperty(value);
}
public int WindowHeight
{
get => GetProperty(600);
set => SetProperty(value);
}
public bool IsPaneOpen
{
get => _isPaneOpen;
set => SetProperty(ref _isPaneOpen, value);
}
private static void SetTheme(ThemeMode themeMode)
{
ThemeManager.Current.ApplicationTheme = themeMode switch
{
ThemeMode.Light => ApplicationTheme.Light,
ThemeMode.Dark => ApplicationTheme.Dark,
ThemeMode.UseSystemSetting => default,
_ => ThemeManager.Current.ApplicationTheme
};
}
private async Task ShowDialogAsync()
{
var dialog = new ContentDialogExample {Message = WelcomeMessage};
var result = await dialog.ShowAsync().ConfigureAwait(false);
WelcomeMessage = result.ToString();
}
private void BooleanValue_OnChanged(bool obj)
{
VisibilityEnumTest = obj ? Visibility.Visible : Visibility.Collapsed;
}
private void SaveViewModel()
{
var contents = _serializer.Serialize(Values);
if (Path == null)
{
var saveFileDialog = new SaveFileDialog {AddExtension = true, DefaultExt = "*.yaml"};
var result = saveFileDialog.ShowDialog(Application.Current.MainWindow?.Owner);
if (result != true) return;
Path = saveFileDialog.FileName;
}
File.WriteAllText(Path, contents);
}
protected override IEnumerable<(string key, object? value)> GetViewModelItems()
{
var openFileDialog = new OpenFileDialog {AddExtension = true, DefaultExt = "*.yaml"};
var result = openFileDialog.ShowDialog(Application.Current.MainWindow?.Owner);
if (result != true) yield break;
var contents = File.ReadAllText(Path = openFileDialog.FileName);
var obj = _deserializer.Deserialize<Dictionary<string, object>>(contents);
foreach (var (key, value) in obj)
{
yield return (key, DeserializationExtension.Convert(value, ObjectAccessor[key].GetType()));
}
}
}
}

View File

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UseWPF>true</UseWPF>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FastMember" Version="1.5.0" />
<PackageReference Include="ModernWpfUI" Version="0.8.3" />
<PackageReference Include="Prism.DryIoc" Version="7.2.0.1422" />
<PackageReference Include="Prism.Wpf" Version="7.2.0.1422" />
<PackageReference Include="YamlDotNet" Version="8.1.0" />
<PackageReference Include="System.Drawing.Common" Version="4.7.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Controls\Controls.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using FastMember;
using Prism.Mvvm;
namespace ModernWpfPlayground.MvvmStuff
{
public abstract class BaseViewModel : BindableBase
{
protected BaseViewModel()
{
ObjectAccessor = ObjectAccessor.Create(this);
}
private readonly Dictionary<string, object> _values = new Dictionary<string, object>();
protected readonly ObjectAccessor ObjectAccessor;
protected IReadOnlyDictionary<string, object> Values => _values;
protected bool SetProperty<T>(T value, Action<T>? onChanged = null,
[CallerMemberName] string? propertyName = null)
{
if (propertyName == null) throw new ArgumentNullException(nameof(propertyName));
if (_values.TryGetValue(propertyName, out var obj) && Equals(value, obj)) return false;
_values[propertyName] = value!;
RaisePropertyChanged(propertyName);
onChanged?.Invoke(value);
return true;
}
protected T GetProperty<T>(T defaultValue = default, [CallerMemberName] string? propertyName = null)
{
if (propertyName == null) throw new ArgumentNullException(nameof(propertyName));
return Values.TryGetValue(propertyName, out var obj) ? (T)obj : defaultValue;
}
protected void ResetViewModel(Func<string, bool>? predicate = null)
{
IEnumerable<string> keys = _values.Keys;
if (predicate != null) keys = keys.Where(predicate);
foreach (var key in keys)
{
_values.Remove(key);
RaisePropertyChanged(key);
}
}
protected abstract IEnumerable<(string key, object? value)> GetViewModelItems();
protected void LoadViewModel()
{
var keysFromFile = new SortedSet<string>();
foreach (var (key, value) in GetViewModelItems())
{
keysFromFile.Add(key);
ObjectAccessor[key] = value;
}
ResetViewModel(x => !keysFromFile.Contains(x));
}
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Globalization;
namespace ModernWpfPlayground.MvvmStuff
{
public static class DeserializationExtension
{
public static object? Convert(object? value, Type propertyType)
{
if (value is null) return Activator.CreateInstance(propertyType);
if (propertyType.IsEnum && value is string s)
{
return Enum.Parse(propertyType, s);
}
return System.Convert.ChangeType(value, propertyType, CultureInfo.InvariantCulture);
}
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace ModernWpfPlayground
{
public class PixelsToGridLengthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is double d ? new GridLength(d) : new GridLength(1.0, GridUnitType.Auto);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

11
App/ThemeMode.cs Normal file
View File

@ -0,0 +1,11 @@
using System.ComponentModel;
namespace ModernWpfPlayground
{
public enum ThemeMode
{
[Description("Light")] Light,
[Description("Dark")] Dark,
[Description("Use system setting")] UseSystemSetting
}
}