MCSharp
MCSharp

Reputation: 1068

How can the opacity of a program be controled through a settings window in real time?

I am trying to change the Opacity of the main application window through a settings window popup in real time. What is the proper way of doing this?

So far, I have tried using a Slider to output the value to the settings file. When the settings popup is closed, the main window refreshes its opacity property based on the settings file. This method works but I'd like the ability to change the opacity and view the result in real time.

The second method I tried was using a Style and applying it to the MainWindow. Then on slider move, the style would be overridden with the value from the slider. This works in real time. But for whatever reason, the settings popup window opacity is also affected even though no style is applied to it.

Here is a sample project named OpacityTest with a main window, a button to open settings popup and slider to control the program's opacity.

App.xaml:

<Application x:Class="OpacityTest.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <Style TargetType="Window" x:Key="wrapper">
            <Setter Property="OverridesDefaultStyle" Value="false"/>
            <Setter x:Name="opacitySetter" Property="Opacity" Value="1"/>
        </Style>
    </Application.Resources>
</Application>

MainWindow.xaml:

<Window x:Class="OpacityTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" Style="{DynamicResource wrapper}" Background="#FFCDCDCD" AllowsTransparency="True" WindowStyle="None">
    <Grid>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <Button Content="Settings" HorizontalAlignment="Center" VerticalAlignment="Center" Width="75" Click="Button_Click"/>
        </StackPanel>
    </Grid>
</Window>

New window labeled Settings, Settings.xaml:

<Window x:Class="OpacityTest.Settings"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Settings" Height="300" Width="300">
    <Grid>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <Slider x:Name="ChangeTransparency" MinWidth="138" MinHeight="22" VerticalAlignment="Center" Padding="0" Orientation="Horizontal" HorizontalAlignment="Center" Value="1" Minimum=".05" Maximum="1" LargeChange=".01" SmallChange=".01" TickFrequency="100" IsSnapToTickEnabled="False" MouseMove="ChangeTransparency_MouseMove"/>
        </StackPanel>
    </Grid>
</Window>

MainWindow.xaml.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace OpacityTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Settings settings = new Settings();
            settings.ShowDialog();
        }
    }
}

Settings.xaml.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;

    namespace OpacityTest
    {
        /// <summary>
        /// Interaction logic for Settings.xaml
        /// </summary>
        public partial class Settings : Window
        {
            public Settings()
            {
                InitializeComponent();
            }

            private void ChangeTransparency_MouseMove(object sender, MouseEventArgs e)
            {
                Style style = new Style { TargetType = typeof(Window) };
                style.Setters.Add(new Setter(OpacityProperty, Opacity = ChangeTransparency.Value));
                Application.Current.Resources["wrapper"] = style;
            }
        }
    }

Upvotes: 2

Views: 430

Answers (1)

Tim S.
Tim S.

Reputation: 56556

It looks like your Style is behaving as if it were declared in a XAML file in a way that affects all Windows, not just the wrapper style, e.g.

<Style TargetType="Window"> ... </Style>

Instead of:

<Style TargetType="Window" x:Key="wrapper"> ... </Style>

I'm not immediately sure of how to declare it the way you're trying to, but a much easier way to accomplish what you're trying to do is to put this in MainWindow.xaml.cs:

private void Button_Click(object sender, RoutedEventArgs e)
{
    Settings settings = new Settings();
    this.SetBinding(OpacityProperty,
                  new Binding("Value") { Source = settings.ChangeTransparency });
    settings.ShowDialog();
}

No handler on ChangeTransparency is required this way. The only reason I might consider modifying the Style instead is if you can have multiple MainWindows at once, and want one Settings window (opened from any of them) to control them all at once.

As an aside, if you do find that you need to attach to ChangeTransparency, you should attach a handler to its ValueChanged event instead of MouseMove (while MouseMove will generally work out, it's really not the same; e.g. for keyboard input, only ValueChanged will fire).

If Settings can be used from other windows and/or has more properties, you might wish to change Settings to take a Window (or other type) in its constructor, and set up the binding(s) there instead, to keep your code/logic centralized and clean.

Upvotes: 3

Related Questions