Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for Dialogs crash when app style is set via ThemeManager #1358 #1383

Merged
merged 1 commit into from
Jun 4, 2014

Conversation

GeertvanHorrik
Copy link
Contributor


MOD EDIT:

  • Adding auto-issue-closing statements. *

Fixes #1385
Fixes #1358

MOD EDIT by @Amrykid


@GeertvanHorrik
Copy link
Contributor Author

I cannot see any relevant error messages on the build. What is wrong?

@AzureKitsune
Copy link
Member

The CI needs to build it again because the first time, it restored the nuget packages.

C:\projects\mahapps-metro\samples\MetroDemo\MetroDemo.csproj(342,5): error : The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568.
82 MahApps.Metro.Resources -> C:\projects\mahapps-metro\MahApps.Metro.Resources\bin\Debug\MahApps.Metro.Resources.dll

cc @MahApps/contributors

@flagbug
Copy link
Member

flagbug commented Jun 4, 2014

@Amrykid Ignore the CI, that was just a test of mine and it somehow automatically added notifications to Github

@GeertvanHorrik
Copy link
Contributor Author

Cool, then I hope you can accept this pull request asap. I have committed my customized assemblies to source control, but NuGet keeps "restoring" them ;-)

punker76 added a commit that referenced this pull request Jun 4, 2014
Fix for Dialogs crash when app style is set via ThemeManager #1358
@punker76 punker76 merged commit 4738d8c into MahApps:master Jun 4, 2014
@punker76 punker76 mentioned this pull request Jun 4, 2014
33 tasks
punker76 added a commit that referenced this pull request Jun 4, 2014
- this change brakes the thememanger's default usage
- handle not finding app style
punker76 added a commit that referenced this pull request Jun 4, 2014
@punker76
Copy link
Member

punker76 commented Jun 4, 2014

@GeertvanHorrik i must revert your pr, sorry for this... but it breaks the default thememanager usage.

to handle custom accents or themes you must follow thes rules:

  • copy an original accent or theme res dict, change the colors and include it in your app
  • add these res dict always to the thememanager
  • now switching between accents or themes should work like a sharme

short example (you can look into my simple mahapps demo to see how it works)

<Application x:Class="MahApps.Metro.Simple.Demo.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
  <Application.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
        <ResourceDictionary Source="/Resources/Icons.xaml" />
        <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
        <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
        <ResourceDictionary Source="pack://application:,,,/MahApps.Metro.Simple.Demo;component/CustomAccents/CustomAccent1.xaml" />
        <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </Application.Resources>
</Application>
  public partial class App : Application
  {
      protected override void OnStartup(StartupEventArgs e)
      {
          ThemeManager.AddAccent("CustomAccent1", new Uri("pack://application:,,,/MahApps.Metro.Simple.Demo;component/CustomAccents/CustomAccent1.xaml"));
          ThemeManager.AddAccent("CustomAccent2", new Uri("pack://application:,,,/MahApps.Metro.Simple.Demo;component/CustomAccents/CustomAccent2.xaml"));
          ThemeManager.AddAppTheme("CustomTheme", new Uri("pack://application:,,,/MahApps.Metro.Simple.Demo;component/CustomAccents/CustomTheme.xaml"));

          base.OnStartup(e);
      }
  }
    private void CustomThemeAppButtonClick(object sender, RoutedEventArgs e)
    {
      var theme = ThemeManager.DetectAppStyle(Application.Current);
      ThemeManager.ChangeAppStyle(Application.Current, theme.Item2, ThemeManager.GetAppTheme("CustomTheme"));
    }

    private void CustomAccent1AppButtonClick(object sender, RoutedEventArgs e)
    {
      var theme = ThemeManager.DetectAppStyle(Application.Current);
      ThemeManager.ChangeAppStyle(Application.Current, ThemeManager.GetAccent("CustomAccent1"), theme.Item1);
    }

    private void CustomAccent2AppButtonClick(object sender, RoutedEventArgs e)
    {
      var theme = ThemeManager.DetectAppStyle(Application.Current);
      ThemeManager.ChangeAppStyle(Application.Current, ThemeManager.GetAccent("CustomAccent2"), theme.Item1);
    }

@GeertvanHorrik
Copy link
Contributor Author

The problem is that you check by Source (which is not available on runtime dictionaries). I have the ability to create dynamic accents based on a single color (because that is all you need).

Can you tell me what it breaks? I explicitly added the check at the end to allow the MahApps logic to always be first.

@GeertvanHorrik
Copy link
Contributor Author

If you tell me what gets broken, I can fix that. I think it's not good to require a resource uri (because all you really need is a resource dictionary, not some sort of fixed uri).

@punker76
Copy link
Member

punker76 commented Jun 4, 2014

@GeertvanHorrik look at the main mahapps demo and change the accent (through the menu) with your changes. you will see that nothing happens. the detection gets always your created accent.
i think adding a runtime dynamic accent or theme is not a problem. it's only important to add this to the thememanager.

@punker76
Copy link
Member

punker76 commented Jun 4, 2014

@GeertvanHorrik maybe we need another additional feature to allow adding runtime res dict (-> Orchestra)

@GeertvanHorrik
Copy link
Contributor Author

I will check out your demo and see if I can come up with a full working solution. We would love the code in Orchestra to be contributed to MahApps (I think more people want to be able to set the accent color based on a single color). Let me know if you are interested in that.

@punker76
Copy link
Member

punker76 commented Jun 5, 2014

@GeertvanHorrik i updated my example with this solution (maybe not the best, but it works)

public static void SetThemeColor(Color color, bool changeImmediately = false)
{
    //Log.Info("Setting theme to '{0}'", color.ToString());

    //<Color x:Key="HighlightColor">
    //    #800080
    //</Color>
    //<Color x:Key="AccentColor">
    //    #CC800080
    //</Color>
    //<Color x:Key="AccentColor2">
    //    #99800080
    //</Color>
    //<Color x:Key="AccentColor3">
    //    #66800080
    //</Color>
    //<Color x:Key="AccentColor4">
    //    #33800080
    //</Color>

    //<SolidColorBrush x:Key="HighlightBrush" Color="{StaticResource HighlightColor}" />
    //<SolidColorBrush x:Key="AccentColorBrush" Color="{StaticResource AccentColor}" />
    //<SolidColorBrush x:Key="AccentColorBrush2" Color="{StaticResource AccentColor2}" />
    //<SolidColorBrush x:Key="AccentColorBrush3" Color="{StaticResource AccentColor3}" />
    //<SolidColorBrush x:Key="AccentColorBrush4" Color="{StaticResource AccentColor4}" />
    //<SolidColorBrush x:Key="WindowTitleColorBrush" Color="{StaticResource AccentColor}" />
    //<SolidColorBrush x:Key="AccentSelectedColorBrush" Color="White" />
    //<LinearGradientBrush x:Key="ProgressBrush" EndPoint="0.001,0.5" StartPoint="1.002,0.5">
    //    <GradientStop Color="{StaticResource HighlightColor}" Offset="0" />
    //    <GradientStop Color="{StaticResource AccentColor3}" Offset="1" />
    //</LinearGradientBrush>
    //<SolidColorBrush x:Key="CheckmarkFill" Color="{StaticResource AccentColor}" />
    //<SolidColorBrush x:Key="RightArrowFill" Color="{StaticResource AccentColor}" />

    //<Color x:Key="IdealForegroundColor">
    //    Black
    //</Color>
    //<SolidColorBrush x:Key="IdealForegroundColorBrush" Color="{StaticResource IdealForegroundColor}" />

    //Log.Debug("Creating runtime accent resource dictionary");

    var resourceDictionary = new ResourceDictionary();

    resourceDictionary.Add("HighlightColor", color);
    resourceDictionary.Add("AccentColor", Color.FromArgb((byte)(204), color.R, color.G, color.B));
    resourceDictionary.Add("AccentColor2", Color.FromArgb((byte)(153), color.R, color.G, color.B));
    resourceDictionary.Add("AccentColor3", Color.FromArgb((byte)(102), color.R, color.G, color.B));
    resourceDictionary.Add("AccentColor4", Color.FromArgb((byte)(51), color.R, color.G, color.B));

    resourceDictionary.Add("HighlightBrush", new SolidColorBrush((Color)resourceDictionary["HighlightColor"]));
    resourceDictionary.Add("AccentColorBrush", new SolidColorBrush((Color)resourceDictionary["AccentColor"]));
    resourceDictionary.Add("AccentColorBrush2", new SolidColorBrush((Color)resourceDictionary["AccentColor2"]));
    resourceDictionary.Add("AccentColorBrush3", new SolidColorBrush((Color)resourceDictionary["AccentColor3"]));
    resourceDictionary.Add("AccentColorBrush4", new SolidColorBrush((Color)resourceDictionary["AccentColor4"]));
    resourceDictionary.Add("WindowTitleColorBrush", new SolidColorBrush((Color)resourceDictionary["AccentColor"]));
    resourceDictionary.Add("AccentSelectedColorBrush", new SolidColorBrush(Colors.White));

    resourceDictionary.Add("ProgressBrush", new LinearGradientBrush(new GradientStopCollection(new[]
          {
              new GradientStop((Color)resourceDictionary["HighlightColor"], 0),
              new GradientStop((Color)resourceDictionary["AccentColor3"], 1)
          }), new Point(0.001, 0.5), new Point(1.002, 0.5)));

    resourceDictionary.Add("CheckmarkFill", new SolidColorBrush((Color)resourceDictionary["AccentColor"]));
    resourceDictionary.Add("RightArrowFill", new SolidColorBrush((Color)resourceDictionary["AccentColor"]));

    resourceDictionary.Add("IdealForegroundColor", Colors.Black);
    resourceDictionary.Add("IdealForegroundColorBrush", new SolidColorBrush((Color)resourceDictionary["IdealForegroundColor"]));

    var application = Application.Current;
    var applicationTheme = ThemeManager.AppThemes.First(x => string.Equals(x.Name, "BaseLight"));

    //Log.Debug("Applying theme to MahApps");

    var resDictName = string.Format("ApplicationAccent_{0}.xaml", color.ToString().Replace("#", string.Empty));
    var fileName = Path.Combine(Path.GetTempPath(), resDictName);
    using (var writer = System.Xml.XmlWriter.Create(fileName, new System.Xml.XmlWriterSettings { Indent = true }))
    {
        System.Windows.Markup.XamlWriter.Save(resourceDictionary, writer);
        writer.Close();
    }

    resourceDictionary = new ResourceDictionary() { Source = new Uri(fileName, UriKind.Absolute) };

    var newAccent = new Accent { Name = resDictName, Resources = resourceDictionary };
    ThemeManager.AddAccent(newAccent.Name, newAccent.Resources.Source);
    if (changeImmediately)
    {
      ThemeManager.ChangeAppStyle(application, newAccent, applicationTheme);
    }
}

@GeertvanHorrik
Copy link
Contributor Author

Ok, I can imagine why you do that, but not deleting temp files can hurt your at one point (but ok, this isn't a lot of files :-)). For now I will use this example, thanks for updating it. I think you should still consider adding something like this to MahApps! Great work 👍

@GeertvanHorrik
Copy link
Contributor Author

It still looks to crash when I show a message box / dialog.

@GeertvanHorrik
Copy link
Contributor Author

Sorry for my late reply, was side-tracked. Now looking into a definitive fix.

@GeertvanHorrik
Copy link
Contributor Author

Found the bug! There were 2 issues:

  1. When no resource was found, it was checking out the top level resource dictionary. If you use resources.Contains, it will also check out all children thus that is always a hit. The solution is the check for the actual keys instead of using Contains.
  2. When checking out runtime accents, we need to skip the existing ones that have a source.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants