如何将 XAML 资源用作 Mahapps.Metro 标题栏中的图标?
How To Use a XAML Resource As An Icon In Mahapps.Metro Title Bar?
我有一个小应用程序,使用 Mahapps Metro 框架。我想更改标题栏中的图标,如 connect/disconnect 图标。我如何访问内容或动态绑定它?
这是我的 XAML:
<Controls:MetroWindow x:Class="NFCAgent.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls"
Title="NFC-Agent"
Height="55"
Width="250"
ResizeMode="NoResize"
GlowBrush="{DynamicResource AccentColorBrush}"
WindowStartupLocation="Manual"
Topmost="True"
ShowIconOnTitleBar="True">
<Controls:MetroWindow.LeftWindowCommands>
<Controls:WindowCommands>
<Button IsEnabled="False" >
<StackPanel Orientation="Horizontal">
<Rectangle x:Name="headerLogo" Width="20" Height="20"
Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill"
Visual="{DynamicResource appbar_cupcake}" />
</Rectangle.OpacityMask>
</Rectangle>
</StackPanel>
</Button>
</Controls:WindowCommands>
</Controls:MetroWindow.LeftWindowCommands>
<Grid>
<StackPanel Orientation="Horizontal">
<Rectangle Width="25" Height="25" Margin="4 0">
<Rectangle.Fill>
<VisualBrush Visual="{DynamicRessource appbar_add}" />
</Rectangle.Fill>
</Rectangle>
<TextBlock x:Name="txtStatus" Text="Statusinfo" VerticalAlignment="Center"></TextBlock>
</StackPanel>
</Grid>
补充:我没有 ImageFile(没有 *.ico),我使用 Mahapps.Resources (xaml-Files) 中包含的资源。 Afaik 必须以某种方式替换 Rectangle 的内容 - 但如何替换?
您可以通过将图标资源保留在 ViewModel
中并使用常规绑定来实现:
XAML:
<Controls:MetroWindow x:Class="WpfApplication4.Window4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:local="clr-namespace:WpfApplication4"
mc:Ignorable="d"
BorderThickness="5"
BorderBrush="{DynamicResource AccentColorBrush}"
Title="{Binding MyIcon}" Height="300" Width="300" Loaded="MetroWindow_Loaded">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro.Resources;component/Icons.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Olive.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Controls:MetroWindow.LeftWindowCommands>
<Controls:WindowCommands>
<Rectangle Height="20" Width="20" Fill="{Binding RelativeSource={RelativeSource AncestorType=Controls:WindowCommands}, Path=Foreground}">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill" Visual="{Binding MyResource}" />
</Rectangle.OpacityMask>
</Rectangle>
</Controls:WindowCommands>
</Controls:MetroWindow.LeftWindowCommands>
<Controls:MetroWindow.DataContext>
<local:MyViewModel/>
</Controls:MetroWindow.DataContext>
<Grid>
<Button Content="Change Icon" Click="Button_Click" HorizontalAlignment="Center" VerticalAlignment="Center"></Button>
</Grid>
Window:
public partial class Window4 : MetroWindow
{
MyViewModel viewModel;
public Window4()
{
InitializeComponent();
}
private void MetroWindow_Loaded(object sender, RoutedEventArgs e)
{
viewModel = new MyViewModel();
DataContext = viewModel;
viewModel.MyIcon = "appbar_box";
viewModel.MyResource = (Visual)Resources[viewModel.MyIcon];
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (viewModel.MyIcon == "appbar_box")
viewModel.MyIcon = "appbar_add";
else viewModel.MyIcon = "appbar_box";
viewModel.MyResource = (Visual)Resources[viewModel.MyIcon];
}
}
视图模型:
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public MyViewModel()
{
}
private string myIcon;
public string MyIcon
{
get { return myIcon; }
set
{
if (value != myIcon)
{
myIcon = value;
NotifyPropertyChanged();
}
}
}
private Visual myResource;
public Visual MyResource
{
get { return myResource; }
set
{
if (value != myResource)
{
myResource = value;
NotifyPropertyChanged();
}
}
}
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
虽然这个问题的答案已被接受,但这是我的解决方案,它不需要 MetroWindow 部分 class 中的代码(尽管它确实需要在视图模型中引用 System.Windows以及 Application Dispatcher 的使用)。
using System;
using Caliburn.Micro;
using System.Windows.Media;
using System.Windows;
namespace ChangingMahAppsIcon
{
class CHeartbeatViewModel : PropertyChangedBase
{
public Visual IconResource { get; set; }
private System.Timers.Timer m_oHeartbeatTimer;
private ResourceDictionary m_oIconResource;
private bool m_bHeartbeatIsOn = false;
public CHeartbeatViewModel()
{
m_oIconResource = new ResourceDictionary() { Source = new Uri(@"Resources\Icons.xaml", UriKind.Relative) };
m_oHeartbeatTimer = new System.Timers.Timer(1000);
m_oHeartbeatTimer.Elapsed += UpdateHeartbeat;
m_oHeartbeatTimer.Start();
}
private void UpdateHeartbeat(object sender, System.Timers.ElapsedEventArgs e)
{
string strIconName;
m_bHeartbeatIsOn = !m_bHeartbeatIsOn;
if (m_bHeartbeatIsOn)
{
strIconName = "appbar_heart";
}
else
{
strIconName = "appbar_heart_outline";
}
Application.Current.Dispatcher.Invoke((System.Action)delegate {
IconResource = (Visual)m_oIconResource[strIconName];
NotifyOfPropertyChange(() => IconResource);
});
}
}
}
我有一个小应用程序,使用 Mahapps Metro 框架。我想更改标题栏中的图标,如 connect/disconnect 图标。我如何访问内容或动态绑定它?
这是我的 XAML:
<Controls:MetroWindow x:Class="NFCAgent.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls"
Title="NFC-Agent"
Height="55"
Width="250"
ResizeMode="NoResize"
GlowBrush="{DynamicResource AccentColorBrush}"
WindowStartupLocation="Manual"
Topmost="True"
ShowIconOnTitleBar="True">
<Controls:MetroWindow.LeftWindowCommands>
<Controls:WindowCommands>
<Button IsEnabled="False" >
<StackPanel Orientation="Horizontal">
<Rectangle x:Name="headerLogo" Width="20" Height="20"
Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill"
Visual="{DynamicResource appbar_cupcake}" />
</Rectangle.OpacityMask>
</Rectangle>
</StackPanel>
</Button>
</Controls:WindowCommands>
</Controls:MetroWindow.LeftWindowCommands>
<Grid>
<StackPanel Orientation="Horizontal">
<Rectangle Width="25" Height="25" Margin="4 0">
<Rectangle.Fill>
<VisualBrush Visual="{DynamicRessource appbar_add}" />
</Rectangle.Fill>
</Rectangle>
<TextBlock x:Name="txtStatus" Text="Statusinfo" VerticalAlignment="Center"></TextBlock>
</StackPanel>
</Grid>
补充:我没有 ImageFile(没有 *.ico),我使用 Mahapps.Resources (xaml-Files) 中包含的资源。 Afaik 必须以某种方式替换 Rectangle 的内容 - 但如何替换?
您可以通过将图标资源保留在 ViewModel
中并使用常规绑定来实现:
XAML:
<Controls:MetroWindow x:Class="WpfApplication4.Window4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:local="clr-namespace:WpfApplication4"
mc:Ignorable="d"
BorderThickness="5"
BorderBrush="{DynamicResource AccentColorBrush}"
Title="{Binding MyIcon}" Height="300" Width="300" Loaded="MetroWindow_Loaded">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro.Resources;component/Icons.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Olive.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Controls:MetroWindow.LeftWindowCommands>
<Controls:WindowCommands>
<Rectangle Height="20" Width="20" Fill="{Binding RelativeSource={RelativeSource AncestorType=Controls:WindowCommands}, Path=Foreground}">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill" Visual="{Binding MyResource}" />
</Rectangle.OpacityMask>
</Rectangle>
</Controls:WindowCommands>
</Controls:MetroWindow.LeftWindowCommands>
<Controls:MetroWindow.DataContext>
<local:MyViewModel/>
</Controls:MetroWindow.DataContext>
<Grid>
<Button Content="Change Icon" Click="Button_Click" HorizontalAlignment="Center" VerticalAlignment="Center"></Button>
</Grid>
Window:
public partial class Window4 : MetroWindow
{
MyViewModel viewModel;
public Window4()
{
InitializeComponent();
}
private void MetroWindow_Loaded(object sender, RoutedEventArgs e)
{
viewModel = new MyViewModel();
DataContext = viewModel;
viewModel.MyIcon = "appbar_box";
viewModel.MyResource = (Visual)Resources[viewModel.MyIcon];
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (viewModel.MyIcon == "appbar_box")
viewModel.MyIcon = "appbar_add";
else viewModel.MyIcon = "appbar_box";
viewModel.MyResource = (Visual)Resources[viewModel.MyIcon];
}
}
视图模型:
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public MyViewModel()
{
}
private string myIcon;
public string MyIcon
{
get { return myIcon; }
set
{
if (value != myIcon)
{
myIcon = value;
NotifyPropertyChanged();
}
}
}
private Visual myResource;
public Visual MyResource
{
get { return myResource; }
set
{
if (value != myResource)
{
myResource = value;
NotifyPropertyChanged();
}
}
}
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
虽然这个问题的答案已被接受,但这是我的解决方案,它不需要 MetroWindow 部分 class 中的代码(尽管它确实需要在视图模型中引用 System.Windows以及 Application Dispatcher 的使用)。
using System;
using Caliburn.Micro;
using System.Windows.Media;
using System.Windows;
namespace ChangingMahAppsIcon
{
class CHeartbeatViewModel : PropertyChangedBase
{
public Visual IconResource { get; set; }
private System.Timers.Timer m_oHeartbeatTimer;
private ResourceDictionary m_oIconResource;
private bool m_bHeartbeatIsOn = false;
public CHeartbeatViewModel()
{
m_oIconResource = new ResourceDictionary() { Source = new Uri(@"Resources\Icons.xaml", UriKind.Relative) };
m_oHeartbeatTimer = new System.Timers.Timer(1000);
m_oHeartbeatTimer.Elapsed += UpdateHeartbeat;
m_oHeartbeatTimer.Start();
}
private void UpdateHeartbeat(object sender, System.Timers.ElapsedEventArgs e)
{
string strIconName;
m_bHeartbeatIsOn = !m_bHeartbeatIsOn;
if (m_bHeartbeatIsOn)
{
strIconName = "appbar_heart";
}
else
{
strIconName = "appbar_heart_outline";
}
Application.Current.Dispatcher.Invoke((System.Action)delegate {
IconResource = (Visual)m_oIconResource[strIconName];
NotifyOfPropertyChange(() => IconResource);
});
}
}
}