Enhance profile settings and UI for monitor controls

Refactor logic to support optional inclusion of brightness, contrast, volume, and color temperature in monitor profiles. Updated `Brightness` and `ColorTemperature` to nullable types and adjusted related logic in `MainViewModel.cs` and `ProfileMonitorSetting.cs`.

Improved the UI in `PowerDisplayPage.xaml` and `ProfileEditorDialog.xaml`:
- Added toggle switches for selectively including settings in profiles.
- Enhanced layout and styling for better user experience.
- Updated context menu and monitor selection visuals.

Enhanced `MonitorSelectionItem.cs` with new `Include` flags and auto-selection suppression. Updated `ProfileEditorViewModel.cs` to validate profiles and ensure at least one setting is included for selected monitors.

Performed general code cleanup for readability and maintainability.
This commit is contained in:
Yu Leng
2025-11-20 15:13:27 +08:00
parent d64bb78727
commit 8aec939c9d
8 changed files with 363 additions and 137 deletions

View File

@@ -602,10 +602,11 @@ public partial class MainViewModel : INotifyPropertyChanged, IDisposable
Logger.LogInfo($"[Profile] Applying settings to monitor '{monitorVm.Name}' (HardwareId: {setting.HardwareId})");
// Apply brightness
if (setting.Brightness >= monitorVm.MinBrightness && setting.Brightness <= monitorVm.MaxBrightness)
// Apply brightness if included in profile
if (setting.Brightness.HasValue &&
setting.Brightness.Value >= monitorVm.MinBrightness && setting.Brightness.Value <= monitorVm.MaxBrightness)
{
updateTasks.Add(monitorVm.SetBrightnessAsync(setting.Brightness, immediate: true, fromProfile: true));
updateTasks.Add(monitorVm.SetBrightnessAsync(setting.Brightness.Value, immediate: true, fromProfile: true));
}
// Apply contrast if supported and value provided
@@ -622,10 +623,10 @@ public partial class MainViewModel : INotifyPropertyChanged, IDisposable
updateTasks.Add(monitorVm.SetVolumeAsync(setting.Volume.Value, immediate: true, fromProfile: true));
}
// Apply color temperature
if (setting.ColorTemperature > 0)
// Apply color temperature if included in profile
if (setting.ColorTemperature.HasValue && setting.ColorTemperature.Value > 0)
{
updateTasks.Add(monitorVm.SetColorTemperatureAsync(setting.ColorTemperature, fromProfile: true));
updateTasks.Add(monitorVm.SetColorTemperatureAsync(setting.ColorTemperature.Value, fromProfile: true));
}
}

View File

@@ -15,7 +15,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public string HardwareId { get; set; }
[JsonPropertyName("brightness")]
public int Brightness { get; set; }
public int? Brightness { get; set; }
[JsonPropertyName("contrast")]
public int? Contrast { get; set; }
@@ -24,16 +24,14 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public int? Volume { get; set; }
[JsonPropertyName("colorTemperature")]
public int ColorTemperature { get; set; }
public int? ColorTemperature { get; set; }
public ProfileMonitorSetting()
{
HardwareId = string.Empty;
Brightness = 100;
ColorTemperature = 6500;
}
public ProfileMonitorSetting(string hardwareId, int brightness, int colorTemperature, int? contrast = null, int? volume = null)
public ProfileMonitorSetting(string hardwareId, int? brightness = null, int? colorTemperature = null, int? contrast = null, int? volume = null)
{
HardwareId = hardwareId;
Brightness = brightness;

View File

@@ -37,6 +37,8 @@
HeaderIcon="{ui:FontIcon Glyph=&#xE770;}"
IsClickEnabled="True" />
<tkcontrols:SettingsCard
x:Uid="PowerDisplay_RestoreSettingsOnStartup"
HeaderIcon="{ui:FontIcon Glyph=&#xE7B8;}">
@@ -78,11 +80,11 @@
<Button.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem
Text="Rename"
Click="RenameProfile_Click"
Text="Edit"
Click="EditProfile_Click"
Tag="{x:Bind}">
<MenuFlyoutItem.Icon>
<FontIcon Glyph="&#xE8AC;"/>
<FontIcon Glyph="&#xE70F;"/>
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutItem

View File

@@ -182,7 +182,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
}
}
private async void RenameProfile_Click(object sender, RoutedEventArgs e)
private async void EditProfile_Click(object sender, RoutedEventArgs e)
{
var menuItem = sender as MenuFlyoutItem;
if (menuItem?.Tag is PowerDisplayProfile profile)

View File

@@ -15,144 +15,261 @@
PrimaryButtonClick="ContentDialog_PrimaryButtonClick"
CloseButtonClick="ContentDialog_CloseButtonClick">
<ScrollViewer MaxHeight="600" VerticalScrollBarVisibility="Auto">
<StackPanel Spacing="16">
<!-- Profile Name -->
<StackPanel Spacing="4">
<TextBlock
Text="Profile Name"
Style="{StaticResource BodyStrongTextBlockStyle}" />
<TextBox
x:Name="ProfileNameTextBox"
Text="{x:Bind ViewModel.ProfileName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
PlaceholderText="Enter profile name (e.g., 'Work Setup', 'Gaming')"
MaxLength="50" />
<TextBlock
Text="Leave empty to auto-generate (Profile1, Profile2, etc.)"
Style="{StaticResource CaptionTextBlockStyle}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
</StackPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Monitors Selection -->
<StackPanel Spacing="8">
<TextBlock
Text="Select Monitors to Include"
<!-- Profile Name Section -->
<StackPanel Grid.Row="0" Spacing="4" Margin="0,0,0,24">
<TextBlock
Text="Profile Name"
Style="{StaticResource BodyStrongTextBlockStyle}" />
<TextBox
x:Name="ProfileNameTextBox"
Text="{x:Bind ViewModel.ProfileName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
PlaceholderText="Enter profile name (e.g., 'Gaming Mode', 'Work')"
MaxLength="50" />
<TextBlock
Text="Leave empty to auto-generate"
Style="{StaticResource CaptionTextBlockStyle}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
</StackPanel>
<!-- Monitors List -->
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" Padding="0,0,16,0">
<StackPanel Spacing="16">
<TextBlock
Text="Select Monitors"
Style="{StaticResource BodyStrongTextBlockStyle}" />
<TextBlock
Text="At least one monitor must be selected"
Style="{StaticResource CaptionTextBlockStyle}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Visibility="{x:Bind ViewModel.HasSelectedMonitors, Mode=OneWay, Converter={StaticResource ReverseBoolToVisibilityConverter}}" />
<ItemsControl ItemsSource="{x:Bind ViewModel.Monitors, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="viewmodels:MonitorSelectionItem">
<Expander
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
IsExpanded="{x:Bind IsSelected, Mode=TwoWay}"
Margin="0,0,0,8">
<Expander.Header>
<Grid>
<Grid Margin="0,0,0,12">
<!-- Unselected State -->
<Border
CornerRadius="8"
BorderThickness="1"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
Visibility="{x:Bind IsSelected, Mode=OneWay, Converter={StaticResource ReverseBoolToVisibilityConverter}}">
<Grid Padding="16,12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<CheckBox
IsChecked="{x:Bind IsSelected, Mode=TwoWay}"
Margin="0,0,12,0" />
<StackPanel Grid.Column="1" Orientation="Vertical">
Margin="0,0,12,0"
VerticalAlignment="Center"/>
<StackPanel Grid.Column="1" VerticalAlignment="Center">
<TextBlock
Text="{x:Bind Monitor.Name}"
Style="{StaticResource BodyStrongTextBlockStyle}" />
Text="{x:Bind Monitor.Name}"
Style="{StaticResource BodyStrongTextBlockStyle}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
<TextBlock
Text="{x:Bind Monitor.HardwareId}"
Style="{StaticResource CaptionTextBlockStyle}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
Text="{x:Bind Monitor.HardwareId}"
Style="{StaticResource CaptionTextBlockStyle}"
Foreground="{ThemeResource TextFillColorTertiaryBrush}" />
</StackPanel>
</Grid>
</Expander.Header>
</Border>
<StackPanel Spacing="12" Padding="32,8,8,8">
<!-- Brightness -->
<StackPanel Spacing="4">
<Grid>
<TextBlock Text="Brightness" />
<TextBlock
Text="{x:Bind Brightness, Mode=OneWay}"
HorizontalAlignment="Right"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}" />
<!-- Selected State -->
<Border
CornerRadius="8"
BorderThickness="1"
BorderBrush="{ThemeResource AccentControlElevationBorderBrush}"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
Visibility="{x:Bind IsSelected, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
<StackPanel>
<!-- Header: Monitor Selection -->
<Grid Padding="16,12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<CheckBox
IsChecked="{x:Bind IsSelected, Mode=TwoWay}"
Margin="0,0,12,0"
VerticalAlignment="Center"/>
<StackPanel Grid.Column="1" VerticalAlignment="Center">
<TextBlock
Text="{x:Bind Monitor.Name}"
Style="{StaticResource BodyStrongTextBlockStyle}" />
<TextBlock
Text="{x:Bind Monitor.HardwareId}"
Style="{StaticResource CaptionTextBlockStyle}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
</StackPanel>
</Grid>
<Slider
Value="{x:Bind Brightness, Mode=TwoWay}"
Minimum="0"
Maximum="100"
StepFrequency="1"
IsEnabled="{x:Bind IsSelected, Mode=OneWay}" />
</StackPanel>
<!-- Color Temperature -->
<StackPanel
Spacing="4"
Visibility="{x:Bind SupportsColorTemperature, Converter={StaticResource BoolToVisibilityConverter}}">
<Grid>
<TextBlock Text="Color Temperature" />
<TextBlock
Text="{x:Bind ColorTemperature, Mode=OneWay}"
HorizontalAlignment="Right"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}" />
</Grid>
<Slider
Value="{x:Bind ColorTemperature, Mode=TwoWay}"
Minimum="4000"
Maximum="10000"
StepFrequency="100"
IsEnabled="{x:Bind IsSelected, Mode=OneWay}" />
</StackPanel>
<!-- Content: Settings -->
<StackPanel
Padding="20,0,20,20"
Spacing="0">
<MenuFlyoutSeparator Margin="-20,0,-20,16" />
<!-- Contrast -->
<StackPanel
Spacing="4"
Visibility="{x:Bind SupportsContrast, Converter={StaticResource BoolToVisibilityConverter}}">
<Grid>
<TextBlock Text="Contrast" />
<TextBlock
Text="{x:Bind Contrast, Mode=OneWay}"
HorizontalAlignment="Right"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}" />
</Grid>
<Slider
Value="{x:Bind Contrast, Mode=TwoWay}"
Minimum="0"
Maximum="100"
StepFrequency="1"
IsEnabled="{x:Bind IsSelected, Mode=OneWay}" />
</StackPanel>
<!-- Brightness Row -->
<Grid Margin="0,0,0,12" Visibility="{x:Bind Monitor.SupportsBrightness, Converter={StaticResource BoolToVisibilityConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="40" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Spacing="12">
<FontIcon Glyph="&#xE706;" FontSize="16" Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
<TextBlock Text="Brightness" VerticalAlignment="Center"/>
</StackPanel>
<Slider
Grid.Column="1"
Value="{x:Bind Brightness, Mode=TwoWay}"
Minimum="0" Maximum="100"
Margin="12,0,12,0"
VerticalAlignment="Center"/>
<TextBlock
Grid.Column="2"
Text="{x:Bind Brightness, Mode=OneWay}"
VerticalAlignment="Center"
TextAlignment="Right"
Margin="0,0,8,0"/>
<ToggleSwitch
Grid.Column="3"
IsOn="{x:Bind IncludeBrightness, Mode=TwoWay}"
OnContent="" OffContent=""
MinWidth="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"/>
</Grid>
<!-- Volume -->
<StackPanel
Spacing="4"
Visibility="{x:Bind SupportsVolume, Converter={StaticResource BoolToVisibilityConverter}}">
<Grid>
<TextBlock Text="Volume" />
<TextBlock
Text="{x:Bind Volume, Mode=OneWay}"
HorizontalAlignment="Right"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}" />
</Grid>
<Slider
Value="{x:Bind Volume, Mode=TwoWay}"
Minimum="0"
Maximum="100"
StepFrequency="1"
IsEnabled="{x:Bind IsSelected, Mode=OneWay}" />
<!-- Contrast Row -->
<Grid Margin="0,0,0,12" Visibility="{x:Bind Monitor.SupportsContrast, Converter={StaticResource BoolToVisibilityConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="40" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Spacing="12">
<FontIcon Glyph="&#xE793;" FontSize="16" Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
<TextBlock Text="Contrast" VerticalAlignment="Center"/>
</StackPanel>
<Slider
Grid.Column="1"
Value="{x:Bind Contrast, Mode=TwoWay}"
Minimum="0" Maximum="100"
Margin="12,0,12,0"
VerticalAlignment="Center"/>
<TextBlock
Grid.Column="2"
Text="{x:Bind Contrast, Mode=OneWay}"
VerticalAlignment="Center"
TextAlignment="Right"
Margin="0,0,8,0"/>
<ToggleSwitch
Grid.Column="3"
IsOn="{x:Bind IncludeContrast, Mode=TwoWay}"
OnContent="" OffContent=""
MinWidth="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"/>
</Grid>
<!-- Volume Row -->
<Grid Margin="0,0,0,12" Visibility="{x:Bind Monitor.SupportsVolume, Converter={StaticResource BoolToVisibilityConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="40" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Spacing="12">
<FontIcon Glyph="&#xE767;" FontSize="16" Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
<TextBlock Text="Volume" VerticalAlignment="Center"/>
</StackPanel>
<Slider
Grid.Column="1"
Value="{x:Bind Volume, Mode=TwoWay}"
Minimum="0" Maximum="100"
Margin="12,0,12,0"
VerticalAlignment="Center"/>
<TextBlock
Grid.Column="2"
Text="{x:Bind Volume, Mode=OneWay}"
VerticalAlignment="Center"
TextAlignment="Right"
Margin="0,0,8,0"/>
<ToggleSwitch
Grid.Column="3"
IsOn="{x:Bind IncludeVolume, Mode=TwoWay}"
OnContent="" OffContent=""
MinWidth="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"/>
</Grid>
<!-- Color Temperature Row -->
<Grid Margin="0,0,0,0" Visibility="{x:Bind Monitor.SupportsColorTemperature, Converter={StaticResource BoolToVisibilityConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="40" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Spacing="12">
<FontIcon Glyph="&#xE790;" FontSize="16" Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
<TextBlock Text="Color Temp" VerticalAlignment="Center"/>
</StackPanel>
<ComboBox
Grid.Column="1"
HorizontalAlignment="Stretch"
Margin="12,0,12,0"
MinWidth="160"
ItemsSource="{x:Bind Monitor.ColorPresetsForDisplay, Mode=OneWay}"
SelectedValue="{x:Bind ColorTemperature, Mode=TwoWay}"
SelectedValuePath="VcpValue"
DisplayMemberPath="DisplayName"
PlaceholderText="Select..."
VerticalAlignment="Center" />
<!-- Spacer to match layout -->
<Grid Grid.Column="2" />
<ToggleSwitch
Grid.Column="3"
IsOn="{x:Bind IncludeColorTemperature, Mode=TwoWay}"
OnContent="" OffContent=""
MinWidth="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"/>
</Grid>
</StackPanel>
</StackPanel>
</StackPanel>
</Expander>
</Border>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</StackPanel>
</ScrollViewer>
</ScrollViewer>
</Grid>
</ContentDialog>

View File

@@ -61,16 +61,32 @@ namespace Microsoft.PowerToys.Settings.UI.Views
if (monitorItem != null)
{
monitorItem.IsSelected = true;
monitorItem.Brightness = monitorSetting.Brightness;
monitorItem.ColorTemperature = monitorSetting.ColorTemperature;
// Set brightness if included in profile
if (monitorSetting.Brightness.HasValue)
{
monitorItem.IncludeBrightness = true;
monitorItem.Brightness = monitorSetting.Brightness.Value;
}
// Set color temperature if included in profile
if (monitorSetting.ColorTemperature.HasValue)
{
monitorItem.IncludeColorTemperature = true;
monitorItem.ColorTemperature = monitorSetting.ColorTemperature.Value;
}
// Set contrast if included in profile
if (monitorSetting.Contrast.HasValue)
{
monitorItem.IncludeContrast = true;
monitorItem.Contrast = monitorSetting.Contrast.Value;
}
// Set volume if included in profile
if (monitorSetting.Volume.HasValue)
{
monitorItem.IncludeVolume = true;
monitorItem.Volume = monitorSetting.Volume.Value;
}
}

View File

@@ -20,9 +20,15 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
private int _contrast = 50;
private int _volume = 50;
private int _colorTemperature = 6500;
private bool _includeBrightness;
private bool _includeContrast;
private bool _includeVolume;
private bool _includeColorTemperature;
public required MonitorInfo Monitor { get; set; }
public bool SuppressAutoSelection { get; set; }
public bool IsSelected
{
get => _isSelected;
@@ -45,6 +51,10 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
{
_brightness = value;
OnPropertyChanged();
if (!SuppressAutoSelection)
{
IncludeBrightness = true;
}
}
}
}
@@ -58,6 +68,10 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
{
_contrast = value;
OnPropertyChanged();
if (!SuppressAutoSelection)
{
IncludeContrast = true;
}
}
}
}
@@ -71,6 +85,10 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
{
_volume = value;
OnPropertyChanged();
if (!SuppressAutoSelection)
{
IncludeVolume = true;
}
}
}
}
@@ -84,6 +102,10 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
{
_colorTemperature = value;
OnPropertyChanged();
if (!SuppressAutoSelection)
{
IncludeColorTemperature = true;
}
}
}
}
@@ -94,6 +116,58 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
public bool SupportsColorTemperature => Monitor?.SupportsColorTemperature ?? false;
public bool IncludeBrightness
{
get => _includeBrightness;
set
{
if (_includeBrightness != value)
{
_includeBrightness = value;
OnPropertyChanged();
}
}
}
public bool IncludeContrast
{
get => _includeContrast;
set
{
if (_includeContrast != value)
{
_includeContrast = value;
OnPropertyChanged();
}
}
}
public bool IncludeVolume
{
get => _includeVolume;
set
{
if (_includeVolume != value)
{
_includeVolume = value;
OnPropertyChanged();
}
}
}
public bool IncludeColorTemperature
{
get => _includeColorTemperature;
set
{
if (_includeColorTemperature != value)
{
_includeColorTemperature = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)

View File

@@ -30,19 +30,33 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
{
var item = new MonitorSelectionItem
{
SuppressAutoSelection = true,
Monitor = monitor,
IsSelected = false,
Brightness = monitor.CurrentBrightness,
Contrast = 50, // Default value (MonitorInfo doesn't store contrast)
Volume = 50, // Default value (MonitorInfo doesn't store volume)
ColorTemperature = monitor.ColorTemperature,
};
// Subscribe to selection changes
item.SuppressAutoSelection = false;
// Subscribe to selection and checkbox changes
item.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(MonitorSelectionItem.IsSelected))
{
OnPropertyChanged(nameof(CanSave));
OnPropertyChanged(nameof(HasSelectedMonitors));
OnPropertyChanged(nameof(HasValidSettings));
}
else if (e.PropertyName == nameof(MonitorSelectionItem.IncludeBrightness) ||
e.PropertyName == nameof(MonitorSelectionItem.IncludeContrast) ||
e.PropertyName == nameof(MonitorSelectionItem.IncludeVolume) ||
e.PropertyName == nameof(MonitorSelectionItem.IncludeColorTemperature))
{
OnPropertyChanged(nameof(CanSave));
OnPropertyChanged(nameof(HasValidSettings));
}
};
@@ -79,7 +93,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
public bool HasSelectedMonitors => _monitors?.Any(m => m.IsSelected) ?? false;
public bool CanSave => !string.IsNullOrWhiteSpace(_profileName) && HasSelectedMonitors;
public bool HasValidSettings => _monitors != null &&
_monitors.Any(m => m.IsSelected) &&
_monitors.Where(m => m.IsSelected).All(m => m.IncludeBrightness || m.IncludeContrast || m.IncludeVolume || m.IncludeColorTemperature);
public bool CanSave => !string.IsNullOrWhiteSpace(_profileName) && HasSelectedMonitors && HasValidSettings;
public PowerDisplayProfile CreateProfile()
{
@@ -87,10 +105,10 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
.Where(m => m.IsSelected)
.Select(m => new ProfileMonitorSetting(
m.Monitor.HardwareId,
m.Brightness,
m.ColorTemperature,
m.SupportsContrast ? (int?)m.Contrast : null,
m.SupportsVolume ? (int?)m.Volume : null))
m.IncludeBrightness ? (int?)m.Brightness : null,
m.IncludeColorTemperature && m.SupportsColorTemperature ? (int?)m.ColorTemperature : null,
m.IncludeContrast && m.SupportsContrast ? (int?)m.Contrast : null,
m.IncludeVolume && m.SupportsVolume ? (int?)m.Volume : null))
.ToList();
return new PowerDisplayProfile(_profileName, settings);