CompilerView swapped to RxUserControl

This commit is contained in:
Justin Swanson 2020-01-20 15:59:26 -06:00
parent f026a666dd
commit d788a3ae95
6 changed files with 200 additions and 57 deletions

View File

@ -54,6 +54,26 @@ namespace Wabbajack
viewProperty: viewProperty);
}
public static IReactiveBinding<TView, TViewModel, (object view, bool isViewModel)> BindStrict<TViewModel, TView, TVMProp, TVProp, TDontCare>(
this TView view,
TViewModel viewModel,
Expression<Func<TViewModel, TVMProp>> vmProperty,
Expression<Func<TView, TVProp>> viewProperty,
IObservable<TDontCare> signalViewUpdate,
Func<TVMProp, TVProp> vmToViewConverter,
Func<TVProp, TVMProp> viewToVmConverter)
where TViewModel : class
where TView : class, IViewFor
{
return view.Bind(
viewModel: viewModel,
vmProperty: vmProperty,
viewProperty: viewProperty,
signalViewUpdate: signalViewUpdate,
vmToViewConverter: vmToViewConverter,
viewToVmConverter: viewToVmConverter);
}
public static IReactiveBinding<TView, TViewModel, (object view, bool isViewModel)> BindStrict<TViewModel, TView, TVMProp, TVProp>(
this TView view,
TViewModel viewModel,
@ -78,7 +98,9 @@ namespace Wabbajack
Expression<Func<TTarget, TValue>> property)
where TTarget : class
{
return @this.BindTo<TValue, TTarget, TValue>(target, property);
return @this
.ObserveOnGuiThread()
.BindTo<TValue, TTarget, TValue>(target, property);
}
/// <summary>

View File

@ -48,9 +48,9 @@ namespace Wabbajack
public ObservableCollectionExtended<IStatusMessage> Log => MWVM.Log;
public ReactiveCommand<Unit, Unit> BackCommand { get; }
public IReactiveCommand GoToModlistCommand { get; }
public IReactiveCommand CloseWhenCompleteCommand { get; }
public IReactiveCommand BeginCommand { get; }
public ReactiveCommand<Unit, Unit> GoToModlistCommand { get; }
public ReactiveCommand<Unit, Unit> CloseWhenCompleteCommand { get; }
public ReactiveCommand<Unit, Unit> BeginCommand { get; }
public FilePickerVM OutputLocation { get; }

View File

@ -40,7 +40,7 @@ namespace Wabbajack
set => SetValue(SettingsHookProperty, value);
}
public static readonly DependencyProperty SettingsHookProperty = DependencyProperty.Register(nameof(SettingsHook), typeof(MainSettings), typeof(CpuView),
new FrameworkPropertyMetadata(default(SettingsVM)));
new FrameworkPropertyMetadata(default(SettingsVM), WireNotifyPropertyChanged));
private bool _ShowingSettings;
public bool ShowingSettings { get => _ShowingSettings; set => this.RaiseAndSetIfChanged(ref _ShowingSettings, value); }

View File

@ -1,4 +1,4 @@
<UserControl
<rxui:ReactiveUserControl
x:Class="Wabbajack.CompilerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@ -8,10 +8,12 @@
xmlns:local="clr-namespace:Wabbajack"
xmlns:mahapps="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:rxui="http://reactiveui.net"
xmlns:wabbacommon="clr-namespace:Wabbajack.Common;assembly=Wabbajack.Common"
d:DataContext="{d:DesignInstance local:CompilerVM}"
d:DesignHeight="450"
d:DesignWidth="800"
x:TypeArguments="local:CompilerVM"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
@ -27,11 +29,11 @@
<ColumnDefinition Width="5" />
</Grid.ColumnDefinitions>
<local:HeatedBackgroundView
x:Name="HeatedBackground"
Grid.Row="0"
Grid.RowSpan="3"
Grid.Column="0"
Grid.ColumnSpan="5"
PercentCompleted="{Binding PercentCompleted}" />
Grid.ColumnSpan="5" />
<Border
x:Name="ModlistDetailsBackground"
Grid.Row="1"
@ -54,30 +56,22 @@
Grid.ColumnSpan="2"
Margin="1,1,5,0"
BorderBrush="{StaticResource HeatedBorderBrush}"
BorderThickness="1"
Opacity="{Binding PercentCompleted}" />
BorderThickness="1" />
<Border
Grid.Row="1"
Grid.Column="3"
BorderBrush="{StaticResource BorderInterestBrush}"
BorderThickness="1,0,1,1">
<local:DetailImageView
Title="{Binding CurrentModlistSettings.ModListName}"
Author="{Binding CurrentModlistSettings.AuthorText}"
BorderThickness="0"
Description="{Binding CurrentModlistSettings.Description}"
Image="{Binding Image}" />
<local:DetailImageView x:Name="DetailImage" BorderThickness="0" />
</Border>
<!-- Comes after image area so shadow can overlay -->
<local:TopProgressView
Title="{Binding CurrentModlistSettings.ModListName, Mode=OneWay}"
x:Name="TopProgressBar"
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="0"
Grid.ColumnSpan="5"
OverhangShadow="True"
ProgressPercent="{Binding PercentCompleted}"
StatePrefixTitle="{Binding ProgressTitle}" />
OverhangShadow="True" />
<Button
x:Name="BackButton"
Grid.Row="0"
@ -88,23 +82,21 @@
Margin="12,5,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Command="{Binding BackCommand}"
Style="{StaticResource IconCircleButtonStyle}"
ToolTip="Back to main menu">
<icon:PackIconMaterial Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}" Kind="ArrowLeft" />
</Button>
<ScrollViewer
x:Name="SettingsScrollViewer"
Grid.Row="1"
Grid.Column="1"
Margin="5"
Background="Transparent"
HorizontalScrollBarVisibility="Disabled"
IsEnabled="{Binding Compiling, Converter={StaticResource InverseBooleanConverter}}"
VerticalScrollBarVisibility="Auto">
<StackPanel
Margin="0,5,0,0"
Background="Transparent"
DataContext="{Binding CurrentModlistSettings}"
Orientation="Vertical">
<StackPanel.Resources>
<Thickness
@ -128,26 +120,26 @@
</Style>
</StackPanel.Resources>
<TextBlock Margin="{StaticResource TitleMargin}" Text="ModList Name" />
<TextBox Style="{StaticResource ValueStyle}" Text="{Binding ModListName, UpdateSourceTrigger=PropertyChanged}" />
<TextBox x:Name="ModListNameSetting" Style="{StaticResource ValueStyle}" />
<TextBlock Margin="{StaticResource TitleMargin}" Text="Author" />
<TextBox Style="{StaticResource ValueStyle}" Text="{Binding AuthorText, UpdateSourceTrigger=PropertyChanged}" />
<TextBox x:Name="AuthorNameSetting" Style="{StaticResource ValueStyle}" />
<TextBlock Margin="{StaticResource TitleMargin}" Text="Description" />
<TextBox
x:Name="DescriptionSetting"
Height="150"
mahapps:TextBoxHelper.Watermark="(700 characters max)"
AcceptsReturn="True"
AcceptsTab="False"
MaxLength="700"
Style="{StaticResource ValueStyle}"
Text="{Binding Description, UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap" />
<TextBlock Margin="{StaticResource TitleMargin}" Text="Image" />
<local:FilePicker
PickerVM="{Binding ImagePath}"
x:Name="ImageFilePicker"
Style="{StaticResource PickerStyle}"
ToolTip="Path to an image to display for the modlist." />
<TextBlock Margin="{StaticResource TitleMargin}" Text="Website" />
<TextBox Style="{StaticResource ValueStyle}" Text="{Binding Website, UpdateSourceTrigger=PropertyChanged}" />
<TextBox x:Name="WebsiteSetting" Style="{StaticResource ValueStyle}" />
<TextBlock
Margin="{StaticResource TitleMargin}"
Text="Readme"
@ -159,30 +151,28 @@
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<local:FilePicker
x:Name="ReadmeFilePickerSetting"
Grid.Column="0"
Height="27"
Margin="0,0,3,0"
VerticalAlignment="Center"
PickerVM="{Binding ReadmeFilePath}"
ToolTip="Path to a readme file."
Visibility="{Binding ReadmeIsWebsite, Converter={StaticResource bool2VisibilityConverter}, ConverterParameter=False}" />
ToolTip="Path to a readme file." />
<TextBox
x:Name="ReadmeWebsiteSetting"
Grid.Column="0"
Height="27"
Margin="0,0,3,0"
VerticalAlignment="Center"
Text="{Binding ReadmeWebsite}"
ToolTip="Readme website"
Visibility="{Binding ReadmeIsWebsite, Converter={StaticResource bool2VisibilityConverter}}" />
ToolTip="Readme website" />
<Button
x:Name="SwapToReadmeWebsiteButton"
Grid.Column="1"
Width="27"
Command="{Binding SwapToWebsiteReadmeCommand}"
ToolTip="Set readme to be a website">
<Button.Style>
<Style BasedOn="{StaticResource IconBareButtonStyle}" TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding ReadmeIsWebsite}" Value="True">
<DataTrigger Binding="{Binding CurrentModlistSettings.ReadmeIsWebsite}" Value="True">
<Setter Property="Foreground" Value="{StaticResource SecondaryBrush}" />
</DataTrigger>
</Style.Triggers>
@ -194,14 +184,14 @@
Kind="Web" />
</Button>
<Button
x:Name="SwapToReadmeFileButton"
Grid.Column="2"
Width="27"
Command="{Binding SwapToTextReadmeCommand}"
ToolTip="Source readme from a local file (txt | html)">
<Button.Style>
<Style BasedOn="{StaticResource IconBareButtonStyle}" TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding ReadmeIsWebsite}" Value="False">
<DataTrigger Binding="{Binding CurrentModlistSettings.ReadmeIsWebsite}" Value="False">
<Setter Property="Foreground" Value="{StaticResource SecondaryBrush}" />
</DataTrigger>
</Style.Triggers>
@ -228,10 +218,10 @@
Grid.ColumnSpan="5"
MaxWidth="1000">
<Grid
x:Name="BottomCompilerSettingsGrid"
Margin="35,0,35,0"
VerticalAlignment="Center"
ClipToBounds="False"
Visibility="{Binding StartedCompilation, Converter={StaticResource bool2VisibilityConverter}, ConverterParameter=False}">
ClipToBounds="False">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
@ -254,6 +244,7 @@
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<local:ImageRadioButtonView
x:Name="MO2CompilerButton"
Grid.Row="0"
Height="35"
Margin="4"
@ -263,6 +254,7 @@
</local:ImageRadioButtonView.Image>
</local:ImageRadioButtonView>
<local:ImageRadioButtonView
x:Name="VortexCompilerButton"
Grid.Row="1"
Height="35"
Margin="4"
@ -273,9 +265,9 @@
</local:ImageRadioButtonView>
</Grid>
<ContentPresenter
x:Name="CustomCompilerSettingsPresenter"
Grid.Row="1"
Grid.Column="1"
Content="{Binding Compiler}">
Grid.Column="1">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type local:MO2CompilerVM}">
<local:MO2CompilerConfigView />
@ -286,38 +278,36 @@
</ContentPresenter.Resources>
</ContentPresenter>
<local:BeginButton
x:Name="BeginButton"
Grid.Row="0"
Grid.RowSpan="3"
Grid.Column="5"
Command="{Binding BeginCommand}" />
Grid.Column="5" />
</Grid>
</Grid>
<Grid
x:Name="MidCompilationGrid"
Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="5"
Margin="5"
Visibility="{Binding StartedCompilation, Converter={StaticResource bool2VisibilityConverter}, FallbackValue=Hidden}">
Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<local:LogView Grid.Column="0" ProgressPercent="{Binding PercentCompleted, Mode=OneWay}" />
<local:LogView x:Name="LogView" Grid.Column="0" />
<local:CpuView
x:Name="CpuView"
Grid.Column="2"
ProgressPercent="{Binding PercentCompleted, Mode=OneWay}"
SettingsHook="{Binding MWVM.Settings}"
ViewModel="{Binding}"
Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsNotNullVisibilityConverter}, ConverterParameter=False}" />
<local:AttentionBorder Grid.Column="2" Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsNotNullVisibilityConverter}}">
ViewModel="{Binding}"/>
<local:AttentionBorder x:Name="UserInterventionsControl" Grid.Column="2">
<local:AttentionBorder.DisplayContent>
<Grid>
<local:ConfirmationInterventionView DataContext="{Binding ActiveGlobalUserIntervention}" Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsTypeVisibilityConverter}, ConverterParameter={x:Type common:ConfirmationIntervention}}" />
</Grid>
</local:AttentionBorder.DisplayContent>
</local:AttentionBorder>
<local:CompilationCompleteView Grid.Column="2" Visibility="{Binding Completed, Converter={StaticResource IsNotNullVisibilityConverter}, FallbackValue=Collapsed}" />
<local:CompilationCompleteView x:Name="CompilationComplete" Grid.Column="2" />
</Grid>
</Grid>
</UserControl>
</rxui:ReactiveUserControl>

View File

@ -1,15 +1,146 @@
using System.Windows.Controls;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Windows.Controls;
using ReactiveUI;
using System.Windows;
using Wabbajack.Common;
namespace Wabbajack
{
/// <summary>
/// Interaction logic for CompilerView.xaml
/// </summary>
public partial class CompilerView : UserControl
public partial class CompilerView : ReactiveUserControl<CompilerVM>
{
public CompilerView()
{
InitializeComponent();
this.WhenActivated(dispose =>
{
// Bind percent completed chanes
this.WhenAny(x => x.ViewModel.PercentCompleted)
.Select(f => (double)f)
.BindToStrict(this, x => x.HeatedBackground.PercentCompleted)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.PercentCompleted)
.Select(f => (double)f)
.BindToStrict(this, x => x.ModlistDetailsHeatBorder.Opacity)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.PercentCompleted)
.Select(f => (double)f)
.BindToStrict(this, x => x.TopProgressBar.ProgressPercent)
.DisposeWith(dispose);
// Bind detail image display
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.ModListName)
.BindToStrict(this, x => x.DetailImage.Title)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.AuthorText)
.BindToStrict(this, x => x.DetailImage.Author)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.Description)
.BindToStrict(this, x => x.DetailImage.Description)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Image)
.BindToStrict(this, x => x.DetailImage.Image)
.DisposeWith(dispose);
// Top Progress Bar
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.ModListName)
.BindToStrict(this, x => x.TopProgressBar.Title)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ProgressTitle)
.BindToStrict(this, x => x.TopProgressBar.StatePrefixTitle)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.BackCommand)
.BindToStrict(this, x => x.BackButton.Command)
.DisposeWith(dispose);
// Settings Panel
this.WhenAny(x => x.ViewModel.Compiling)
.Select(x => !x)
.BindToStrict(this, x => x.SettingsScrollViewer.IsEnabled)
.DisposeWith(dispose);
this.BindStrict(this.ViewModel, x => x.CurrentModlistSettings.ModListName, x => x.ModListNameSetting.Text)
.DisposeWith(dispose);
this.BindStrict(this.ViewModel, x => x.CurrentModlistSettings.AuthorText, x => x.AuthorNameSetting.Text)
.DisposeWith(dispose);
this.BindStrict(this.ViewModel, x => x.CurrentModlistSettings.Description, x => x.DescriptionSetting.Text)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.ImagePath)
.BindToStrict(this, x => x.ImageFilePicker.PickerVM)
.DisposeWith(dispose);
this.BindStrict(this.ViewModel, x => x.CurrentModlistSettings.Website, x => x.WebsiteSetting.Text)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.ReadmeFilePath)
.BindToStrict(this, x => x.ReadmeFilePickerSetting.PickerVM)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.ReadmeIsWebsite)
.Select(isWebsite => isWebsite ? Visibility.Collapsed : Visibility.Visible)
.BindToStrict(this, x => x.ReadmeFilePickerSetting.Visibility)
.DisposeWith(dispose);
this.BindStrict(this.ViewModel, x => x.CurrentModlistSettings.ReadmeWebsite, x => x.ReadmeWebsiteSetting.Text)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.ReadmeIsWebsite)
.Select(isWebsite => isWebsite ? Visibility.Visible : Visibility.Collapsed)
.BindToStrict(this, x => x.ReadmeWebsiteSetting.Visibility)
.DisposeWith(dispose);
this.MarkAsNeeded<CompilerView, CompilerVM, bool>(this.ViewModel, x => x.CurrentModlistSettings.ReadmeIsWebsite);
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.SwapToWebsiteReadmeCommand)
.BindToStrict(this, x => x.SwapToReadmeWebsiteButton.Command)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.SwapToTextReadmeCommand)
.BindToStrict(this, x => x.SwapToReadmeFileButton.Command)
.DisposeWith(dispose);
// Bottom Compiler Settings
this.WhenAny(x => x.ViewModel.StartedCompilation)
.Select(started => started ? Visibility.Hidden : Visibility.Visible)
.BindToStrict(this, x => x.BottomCompilerSettingsGrid.Visibility)
.DisposeWith(dispose);
// Seems to go into an infinite loop between each other. Need to research a better radio button style pattern
//this.BindStrict(this.ViewModel, x => x.SelectedCompilerType, x => x.MO2CompilerButton.IsChecked,
// vmToViewConverter: type => type == ModManager.MO2,
// viewToVmConverter: isChecked => isChecked ? ModManager.MO2 : ModManager.Vortex);
//this.BindStrict(this.ViewModel, x => x.SelectedCompilerType, x => x.MO2CompilerButton.IsChecked,
// vmToViewConverter: type => type == ModManager.Vortex,
// viewToVmConverter: isChecked => isChecked ? ModManager.Vortex : ModManager.MO2);
this.WhenAny(x => x.ViewModel.Compiler)
.BindToStrict(this, x => x.CustomCompilerSettingsPresenter.Content)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.BeginCommand)
.BindToStrict(this, x => x.BeginButton.Command)
.DisposeWith(dispose);
// Mid-compilation panel
this.WhenAny(x => x.ViewModel.StartedCompilation)
.Select(started => started ? Visibility.Visible : Visibility.Hidden)
.BindToStrict(this, x => x.MidCompilationGrid.Visibility)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.PercentCompleted)
.Select(f => (double)f)
.BindToStrict(this, x => x.LogView.ProgressPercent)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.PercentCompleted)
.Select(f => (double)f)
.BindToStrict(this, x => x.CpuView.ProgressPercent)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.MWVM.Settings)
.BindToStrict(this, x => x.CpuView.SettingsHook)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ActiveGlobalUserIntervention)
.Select(x => x == null ? Visibility.Visible : Visibility.Collapsed)
.BindToStrict(this, x => x.CpuView.Visibility)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ActiveGlobalUserIntervention)
.Select(x => x != null ? Visibility.Visible : Visibility.Collapsed)
.BindToStrict(this, x => x.UserInterventionsControl.Visibility)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Completed)
.Select(x => x != null ? Visibility.Visible : Visibility.Collapsed)
.BindToStrict(this, x => x.CompilationComplete.Visibility)
.DisposeWith(dispose);
});
}
}
}

View File

@ -23,7 +23,7 @@
<ContentPresenter Content="{Binding ActivePane}">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type local:CompilerVM}">
<local:CompilerView />
<local:CompilerView ViewModel="{Binding}" />
</DataTemplate>
<DataTemplate DataType="{x:Type local:InstallerVM}">
<local:InstallationView />