mirror of
https://github.com/holgerb83/ModernWpfPlayground.git
synced 2025-06-30 01:40:51 +02:00
Reorganization of files
This commit is contained in:
16
App/App.xaml
Normal file
16
App/App.xaml
Normal 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
22
App/App.xaml.cs
Normal 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
10
App/AssemblyInfo.cs
Normal 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)
|
||||
)]
|
21
App/ContentDialogExample.xaml
Normal file
21
App/ContentDialogExample.xaml
Normal 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=""" /><Run Text="{Binding Message, ElementName=LayoutRoot}" /><Run Text=""" /></TextBlock>
|
||||
</ui:SimpleStackPanel>
|
||||
</ui:ContentDialog>
|
21
App/ContentDialogExample.xaml.cs
Normal file
21
App/ContentDialogExample.xaml.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
7
App/IntellisenseResourceDictionary.cs
Normal file
7
App/IntellisenseResourceDictionary.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace ModernWpfPlayground
|
||||
{
|
||||
public class IntellisenseResourceDictionary : ModernWpf.DesignTime.IntellisenseResourcesBase
|
||||
{
|
||||
|
||||
}
|
||||
}
|
277
App/MainWindow.xaml
Normal file
277
App/MainWindow.xaml
Normal 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
13
App/MainWindow.xaml.cs
Normal 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
167
App/MainWindowViewModel.cs
Normal 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
23
App/ModernWpfPlayground.csproj
Normal file
23
App/ModernWpfPlayground.csproj
Normal 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>
|
65
App/MvvmStuff/BaseViewModel.cs
Normal file
65
App/MvvmStuff/BaseViewModel.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
20
App/MvvmStuff/DeserializationExtension.cs
Normal file
20
App/MvvmStuff/DeserializationExtension.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
20
App/PixelsToGridLengthConverter.cs
Normal file
20
App/PixelsToGridLengthConverter.cs
Normal 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
11
App/ThemeMode.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace ModernWpfPlayground
|
||||
{
|
||||
public enum ThemeMode
|
||||
{
|
||||
[Description("Light")] Light,
|
||||
[Description("Dark")] Dark,
|
||||
[Description("Use system setting")] UseSystemSetting
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user