WPF中如何根据点击条件切换按钮的Path Data(窗口状态切换)
Hey there! Let's get that window icon toggling between Min and Max when the button is clicked. Here's how to adjust your existing WPF code to make this work seamlessly:
We can handle this in two straightforward ways—either by leveraging the window's built-in WindowState property (no extra ViewModel needed) or using an MVVM-friendly approach if that's your preferred architecture.
Option 1: Use Window's WindowState Property (Simplest)
This approach uses data triggers to switch the icon based on whether the window is maximized or not, and a custom command to toggle the window state.
Step 1: Update the Button XAML
Modify your button to bind the icon's data to the window's state, and swap out the MaximizeCommand for a toggle command:
<Button DockPanel.Dock="Right" Command="{StaticResource ToggleWindowStateCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"> <Path x:Name="WindowIconPath" Data="{Binding Data, Source={StaticResource WindowMax}}" /> <!-- Inherit your existing WindowButton style and add the toggle trigger --> <Button.Style> <Style TargetType="Button" BasedOn="{StaticResource WindowButton}"> <Style.Triggers> <DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" Value="Maximized"> <Setter TargetName="WindowIconPath" Property="Data" Value="{Binding Data, Source={StaticResource WindowMin}}" /> </DataTrigger> </Style.Triggers> </Style> </Button.Style> </Button>
Step 2: Create the ToggleWindowStateCommand
Replace your MaximizeCommand with this command that toggles between maximized and normal window states:
public class ToggleWindowStateCommand : ICommand { public bool CanExecute(object parameter) { return parameter is Window; } public void Execute(object parameter) { if (parameter is Window window) { window.WindowState = window.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; } } public event EventHandler CanExecuteChanged { add => CommandManager.RequerySuggested += value; remove => CommandManager.RequerySuggested -= value; } }
Register this command as a static resource in your XAML (just like you did with MaximizeCommand):
<Window.Resources> <local:ToggleWindowStateCommand x:Key="ToggleWindowStateCommand" /> <!-- Keep your existing WindowMax, WindowMin, and WindowButton resources here --> </Window.Resources>
Option 2: MVVM-Friendly Approach
If you're using MVVM and want to bind to a ViewModel property instead of the window's direct state, follow these steps:
Step 1: Add a Property to Your ViewModel
Add a boolean property to track the window state, and implement INotifyPropertyChanged:
private bool _isWindowMaximized; public bool IsWindowMaximized { get => _isWindowMaximized; set { _isWindowMaximized = value; OnPropertyChanged(nameof(IsWindowMaximized)); } } // Implement INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }
Step 2: Update the Toggle Command
Modify the command to update the ViewModel property when toggling the window state:
public class ToggleWindowStateCommand : ICommand { private readonly YourViewModel _viewModel; public ToggleWindowStateCommand(YourViewModel viewModel) { _viewModel = viewModel; } public bool CanExecute(object parameter) => parameter is Window; public void Execute(object parameter) { if (parameter is Window window) { var newState = window.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; window.WindowState = newState; _viewModel.IsWindowMaximized = newState == WindowState.Maximized; } } public event EventHandler CanExecuteChanged { add => CommandManager.RequerySuggested += value; remove => CommandManager.RequerySuggested -= value; } }
Step 3: Bind the Icon with a Converter
Use a BooleanToObjectConverter to switch the icon based on the ViewModel property:
<Window.Resources> <BooleanToObjectConverter x:Key="BoolToWindowIconConverter"> <BooleanToObjectConverter.TrueValue> <Binding Data, Source={StaticResource WindowMin} /> </BooleanToObjectConverter.TrueValue> <BooleanToObjectConverter.FalseValue> <Binding Data, Source={StaticResource WindowMax} /> </BooleanToObjectConverter.FalseValue> </BooleanToObjectConverter> </Window.Resources> <!-- Updated Button XAML --> <Button DockPanel.Dock="Right" Style="{StaticResource WindowButton}" Command="{Binding ToggleWindowStateCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"> <Path Data="{Binding IsWindowMaximized, Converter={StaticResource BoolToWindowIconConverter}}" /> </Button>
Notes
- Your existing
WindowButtonstyle works perfectly with both options—no changes needed there unless you want to tweak hover/pressed states further. - Ensure your
WindowMinandWindowMaxstatic resources are validGeometryobjects (since we're binding to theirDataproperty).
内容的提问来源于stack exchange,提问作者Geeth

