WPF 和 Metro 绑定

WPF and Metro Binding

也许你可以帮忙,我已经尝试了几种不同的方法,但我无法达到预期的结果...

使用 MahApps,我想使用 ComboBoxes 将应用的主题更改为我的 WPF Window。

我使用了 MahApps Demo 中的一些代码并适应了我的 Project/Solution。我可以将主题名称和重音名称加载到我项目中的组合框中,但是现在,当我更改这些组合框中的选择时,我想使用 [=] 中的代码调用存在于 "AccentColorMenuData Class" 中的命令72=] 事件。

所以我的 BaseModel 代码是:

public abstract class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            Debug.Write($"--- CLASS ViewModel Called OnPropertyChanged for object: {propertyName} -------- \n");
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

我的 ViewModel 是:

namespace WPFApplication.Ui
{
    public class AccentColorMenuData
    {
        public string Name { get; set; }
        public Brush BorderColorBrush { get; set; }
        public Brush ColorBrush { get; set; }

        private ICommand changeAccentCommand;

        public ICommand ChangeAccentCommand
        {
            get { return this.changeAccentCommand ?? 
                    (changeAccentCommand = new SimpleCommand { CanExecuteDelegate = x => true, ExecuteDelegate = x => this.DoChangeTheme(x) }); }
        }

        protected virtual void DoChangeTheme(object sender)
        {
            var theme = ThemeManager.DetectAppStyle(Application.Current);
            var accent = ThemeManager.GetAccent(this.Name);
            ThemeManager.ChangeAppStyle(Application.Current, accent, theme.Item1);
        }
    }

    public class AppThemeMenuData : AccentColorMenuData
    {
        protected override void DoChangeTheme(object sender)
        {
            var theme = ThemeManager.DetectAppStyle(Application.Current);
            var appTheme = ThemeManager.GetAppTheme(this.Name);
            ThemeManager.ChangeAppStyle(Application.Current, theme.Item2, appTheme);
        }
    }

    public class RemoteSystemsViewModel : ViewModel
    {
        public List<AccentColorMenuData> AccentColors { get; set; }
        public List<AppThemeMenuData> AppThemes { get; set; }

        public RemoteSystemsViewModel()
        {
            // create accent color menu items for the demo
            this.AccentColors = ThemeManager.Accents
                                            .Select(a => new AccentColorMenuData() { Name = a.Name, ColorBrush = a.Resources["AccentColorBrush"] as Brush })
                                            .ToList();

            // create metro theme color menu items for the demo
            this.AppThemes = ThemeManager.AppThemes
                                           .Select(a => new AppThemeMenuData() { Name = a.Name, BorderColorBrush = a.Resources["BlackColorBrush"] as Brush, ColorBrush = a.Resources["WhiteColorBrush"] as Brush })
                                           .ToList();
        }
    }
}

我的控件代码隐藏(注意我已经有两个组合框的事件函数)

public partial class ConfigurationView : UserControl
    {
        private readonly RemoteSystemsViewModel _viewModel;

        public RemoteSystemsView()
        {
            _viewModel = new RemoteSystemsViewModel();
            InitializeComponent();
            DataContext = _viewModel;
        }

        void SelectionChanged(object sender, SelectionChangedEventArgs e)
        {

        }
    }

最后是我的 XAML 控件内的组合框

<

ComboBox  x:Name="AccentColorsComboBox"
                                           ItemsSource="{Binding AccentColors, Mode=OneWay}"
                                           SelectedValuePath="Name"
                                           DisplayMemberPath="Name"
                                           SelectionChanged="SelectionChanged"
                                           />
                                <ComboBox  x:Name="AppThemesComboBox"
                                           ItemsSource="{Binding AppThemes, Mode=OneWay}"
                                           SelectedValuePath="Name"
                                           DisplayMemberPath="Name"
                                           SelectionChanged="SelectionChanged"
                                           >

                                </ComboBox>

如我所说,组合框填充了正确的信息,但现在,当我更改其中一个或另一个时,我想修改应用的主题。

我已经尝试了很多不同的方法来实现这个但没有成功,也许你可以给一个 "hand"... :)

谢谢。

更新:使用 Dustin 建议

void SelectionChanged(object sender, SelectionChangedEventArgs e)
        {

            string AccentName = this.AccentColorsComboBox.SelectedValue as string;
            string ThemeName = this.AppThemesComboBox.SelectedValue as string;

            if (!string.IsNullOrEmpty(AccentName) && !string.IsNullOrEmpty(ThemeName))
            {
                //Debug.Write($"{AccentName} - {ThemeName}\n");
                ThemeManager.ChangeAppStyle(Application.Current, ThemeManager.GetAccent(AccentName), ThemeManager.GetAppTheme(ThemeName));
            }
}

同时我也做了:

void SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
        ComboBox control = (ComboBox)sender;
        String name = control.Name;
        int index = -1;
        index = control.SelectedIndex;
        if (index > -1)
        {
            var vm = this.DataContext as RemoteSystemsViewModel;

            if (name == "AccentColorsComboBox")
            {
                //Call command from viewmodel     
                if ((vm != null) && (vm.AccentColors[index].ChangeAccentCommand.CanExecute(null)))
                    vm.AccentColors[index].ChangeAccentCommand.Execute(null);
            }
            else
            {
                //Call command from viewmodel     
                if ((vm != null) && (vm.AppThemes[index].ChangeAccentCommand.CanExecute(null)))
                    vm.AppThemes[index].ChangeAccentCommand.Execute(null);
            }
        }

    }

现在我对这两种方法的问题是,当我尝试连续 2 次更改主题时,它只会更改主题,如果我更改一次然后返回并进行另一个选择并再次更改它...重音更改 OK第一次尝试。

有什么想法吗?

UPDATE/SOLUTION 在 C# 中(感谢 DUSTIN 的帮助)

对于 XAML 和 CONTROLS,代码与 Dustin post 在他的 post 中编写的代码相同。

对于 C# 它的去向:

新对象:

public class ApplicationAccentColor
    {
        public string Name { get; set; }
        public SolidColorBrush ColorBrush { get; set; }
    }

VIEWMODEL + CONSTRUCTOR:

public class SystemsViewModel : ViewModel
    {
        /// Open Project Settings and select Settings, then add the following values:
        /// Name= ApplicationThemeName Type = String Scope= User Value = BaseDark
        /// Name= ApplicationAccentName Type = String Scope= User Value = Blue
        /// </summary>

        public IEnumerable<AppTheme> AppThemes { get; set; }
        public IEnumerable<ApplicationAccentColor> AccentColors { get; set; }

        public AppTheme SelectedTheme
        {
            /// Project Global Settings variable
            /// Name= ApplicationThemeName Type = String Scope= User Value = BaseDark
            /// Name= ApplicationAccentName Type = String Scope= User Value = Blue
            get
            {
                /// Get default Values from global varable settings
                return ThemeManager.GetAppTheme(Settings.Default.ApplicationThemeName);
            }
            set
            {
                /// Get default Values from global varable settings, and check if they are the same
                if (object.ReferenceEquals(ThemeManager.GetAppTheme(Settings.Default.ApplicationThemeName), value))
                    return;

                /// Save the new value to global settings variable
                Settings.Default.ApplicationThemeName = value.Name;
                Settings.Default.Save();

                /// Apply the Theme
                ThemeManager.ChangeAppStyle(Application.Current, ThemeManager.GetAccent(SelectedAccent.Name), ThemeManager.GetAppTheme(value.Name));
            }
        }

        public ApplicationAccentColor SelectedAccent
        {
            /// Project Global Settings variable
            /// Name= ApplicationThemeName Type = String Scope= User Value = BaseDark
            /// Name= ApplicationAccentName Type = String Scope= User Value = Blue
            get
            {
                //foreach (ApplicationAccentColor acc in AccentColors)
                //{
                //    if (acc.Name == Settings.Default.ApplicationAccentName)
                //    {
                //        return acc;
                //    }
                //}
                //return new ApplicationAccentColor();

                /// Get default Values from global varable settings
                foreach (ApplicationAccentColor acc in from acc1 in AccentColors where acc1.Name == Settings.Default.ApplicationAccentName select acc1)
                {
                    return acc;
                }
                return new ApplicationAccentColor();
            }
            set
            {
                /// Get default Values from global varable settings, and check if they are the same
                if (object.ReferenceEquals(ThemeManager.GetAccent(Settings.Default.ApplicationAccentName).Name, value.Name))
                    return;

                /// Save the new value to global settings variable
                Settings.Default.ApplicationAccentName = value.Name;
                Settings.Default.Save();

                /// Apply the Theme
                ThemeManager.ChangeAppStyle(Application.Current, ThemeManager.GetAccent(value.Name), ThemeManager.GetAppTheme(SelectedTheme.Name));
            }
        }


        public SystemsViewModel()
        {
            AppThemes = ThemeManager.AppThemes;
            AccentColors = ThemeManager.Accents.Select(a => new ApplicationAccentColor
            {
                Name = a.Name,
                ColorBrush = (SolidColorBrush)a.Resources["AccentColorBrush"]
            }).ToList();


        }

    }

APP.cs(在启动时加载最新设置)

//Loading Values from Global Variables set in Application Settings
            ThemeManager.ChangeAppStyle(Application.Current,
                                        ThemeManager.GetAccent(Settings.Default.ApplicationAccentName.ToString()),
                                        ThemeManager.GetAppTheme(Settings.Default.ApplicationThemeName.ToString()));

谢谢达斯汀的帮助:)

这就是你如何改变 theme/accent

ThemeManager.ChangeAppStyle(Windows.Application.Current, ThemeManager.GetAccent(AccentName), ThemeManager.GetAppTheme(ThemeName))

您已经在 AccentColorMenuData 和 AppThemeMenuData 的 DoChangeTheme 中使用它:AccentColorMenuData

UPDATE/EDIT: 以下是我如何实现这种相同类型的功能。它在 VB 中,但您可以根据需要轻松转换它。作为设置的一部分,我的位于主要 window 的弹出窗口中:

要求您在项目中创建设置,以便此颜色信息在会话中持续存在。您可以在 VS b 中打开我的项目并选择设置。您添加以下设置:

  • 名称= ApplicationThemeName 类型= 字符串范围= 用户值=BaseDark

  • Name=ApplicationAccentName Type=String Scope=User Value=Blue

当然你可以设置默认值。

新对象:

Public Class ApplicationAccentColor
    Public Property Name As String
    Public Property ColorBrush As SolidColorBrush
End Class

在你的视图模型中------------------------

道具:

Public Property AppThemes As New List(Of AppTheme)

Public Property AccentColors As New List(Of ApplicationAccentColor)

Public Property SelectedTheme As AppTheme
    Get
        Return ThemeManager.GetAppTheme(MySettings.Default.ApplicationThemeName)
    End Get
    Set
        If ThemeManager.GetAppTheme(MySettings.Default.ApplicationThemeName) Is Value Then Exit Property
        MySettings.Default.ApplicationThemeName = value.Name
        MySettings.Default.Save()
        ThemeManager.ChangeAppStyle(Windows.Application.Current, ThemeManager.GetAccent(SelectedAccent.Name), ThemeManager.GetAppTheme(value.Name))
    End Set
End Property

Public Property SelectedAccent As ApplicationAccentColor
    Get
        For Each acc As ApplicationAccentColor In From acc1 In AccentColors Where acc1.Name = MySettings.Default.ApplicationAccentName
            Return acc
        Next
        Return New ApplicationAccentColor()
    End Get
    Set
        If ThemeManager.GetAccent(MySettings.Default.ApplicationAccentName).Name is value.Name Then Exit Property
        MySettings.Default.ApplicationAccentName = value.Name
        MySettings.Default.Save()
        ThemeManager.ChangeAppStyle(Windows.Application.Current, ThemeManager.GetAccent(value.Name), ThemeManager.GetAppTheme(SelectedTheme.Name))
    End Set
End Property

构造函数:

AppThemes = ThemeManager.AppThemes
AccentColors = ThemeManager.Accents.Select(Function(a) New ApplicationAccentColor With {.Name = a.Name, .ColorBrush = a.Resources("AccentColorBrush")}).ToList()

XAML:

控制资源:

<DataTemplate x:Key="AppThemeItemsTemplate">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="20"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Ellipse Grid.Column="0" Width="20" Height="20" Fill="{Binding Resources[WhiteColorBrush]}" Stroke="{Binding Resources[BlackColorBrush]}"/>
        <Label Grid.Column="1" Content="{Binding Name}"/>
    </Grid>
</DataTemplate>

<DataTemplate x:Key="AccentColorItemsTemplate">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="20"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Ellipse Grid.Column="0" Width="20" Height="20" Fill="{Binding ColorBrush}"/>
        <Label Grid.Column="1" Content="{Binding Name}"/>
    </Grid>
</DataTemplate>

实际控制:

        <StackPanel Margin="10">
            <Label Content="Theme"/>
            <ComboBox Width="125" HorizontalContentAlignment="Left" HorizontalAlignment="Left" ItemTemplate="{StaticResource AppThemeItemsTemplate}" ItemsSource="{Binding AppThemes}" SelectedItem="{Binding SelectedTheme}"/>
            <Label Content="Accent"/>
            <ComboBox Width="125" HorizontalContentAlignment="Left" HorizontalAlignment="Left" ItemTemplate="{StaticResource AccentColorItemsTemplate}" ItemsSource="{Binding AccentColors}" SelectedItem="{Binding SelectedAccent}"/>
            <Button Style="{StaticResource AccentedSquareButtonStyle}" Command="{Binding RefreshDirectoriesFiles}" Margin="0,20,0,0" Content="Refresh Directories/Files"/>
        </StackPanel>