gpt4 book ai didi

c# - 如何从 ResourceDictionary 设置 Button.Command?

转载 作者:太空宇宙 更新时间:2023-11-03 23:22:07 28 4
gpt4 key购买 nike

我正在尝试自己在 Windows 10 应用程序中实现一个汉堡包按钮。在尝试设置 ButtonCommand 属性(通过样式)时,我的 ResourceDictionary 遇到了一些问题。这是我的代码:

汉堡.xaml

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Octopie.Styles.Hamburger"
xmlns:local="using:Octopie.Styles">

<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Square.xaml"/>
</ResourceDictionary.MergedDictionaries>

<Style x:Key="HamburgerStyle" TargetType="Button" BasedOn="{StaticResource SquareStyle}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Command" Value="{Binding OnClicked}"/> <!--This is the part that's having issues-->
<Setter Property="Content" Value="&#xE700;"/>
<Setter Property="FontFamily" Value="Segoe MDL2 Assets"/>
</Style>
</ResourceDictionary>

Hamburger.xaml.cs

namespace Octopie.Styles
{
public sealed partial class Hamburger : ResourceDictionary
{
public Hamburger()
{
this.InitializeComponent();
}

public ICommand OnClicked => new ClickedCommand();

private class ClickedCommand : ICommand
{
public event EventHandler CanExecuteChanged;

public bool CanExecute(object parameter) =>
parameter is Button;

public void Execute(object parameter)
{
var button = (Button)parameter;

// Walk up the tree until we reach a SplitView
FrameworkElement parent = button;
do
parent = parent.Parent as FrameworkElement;
while (!(parent is SplitView));

var splitView = (SplitView)parent;
splitView.IsPaneOpen = !splitView.IsPaneOpen;
}
}
}
}

由于某些原因,Command 属性的绑定(bind)似乎不起作用;当我在 Execute 方法中设置断点并单击按钮时,永远不会命中断点。我尝试将 DataContext="{Binding RelativeSource={RelativeSource Self}}" 添加到 XAML 文件的顶部,但由于某些原因 ResourceDictionary 似乎不支持DataContext.

tl;dr:我该怎么做才能使 Button.Command 属性正确绑定(bind)到 setter 中的 OnClicked

最佳答案

正如Mike所说,通常我们不会在ResourceDictionary中设置Button.Command。汉堡包按钮不仅可以在 SplitView 中,还可以在另一个地方,然后您可能需要绑定(bind)另一个命令。所以可以引用Mike的建议。

但是如果你确实想在 ResourceDictionary 中设置它,你可以尝试如下:

首先,在你的例子中,你的命令是固定的,你可以将你的 ClickedCommand 声明为一个 public class,然后在 Style 中,将 Command 设置为:

<Setter Property="Command">
<Setter.Value>
<local:ClickedCommand />
</Setter.Value>
</Setter>

在此之后,您可以使用您的命令,但这不会解决您的问题,因为在 ClickedCommand 中,您使用 parameter 来检索 Button,但是parameter并不是Command的“发送者”,而是用CommandParameter传递的object属性(property)。所以我们需要在 Style 中设置它。

但是,UWP 应用程序不支持样式 setter 中的绑定(bind)。见Setter class中的备注 :

The Windows Runtime doesn't support a Binding usage for Setter.Value (the Binding won't evaluate and the Setter has no effect, you won't get errors, but you won't get the desired result either).

解决方法是使用 attached property为您设置代码后面的绑定(bind)。例如:

public class BindingHelper
{
public static readonly DependencyProperty CommandParameterBindingProperty =
DependencyProperty.RegisterAttached(
"CommandParameterBinding", typeof(bool), typeof(BindingHelper),
new PropertyMetadata(null, CommandParameterBindingPropertyChanged));

public static bool GetCommandParameterBinding(DependencyObject obj)
{
return (bool)obj.GetValue(CommandParameterBindingProperty);
}

public static void SetCommandParameterBinding(DependencyObject obj, bool value)
{
obj.SetValue(CommandParameterBindingProperty, value);
}

private static void CommandParameterBindingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue)
{
BindingOperations.SetBinding(d, Button.CommandParameterProperty, new Binding { RelativeSource = new RelativeSource() { Mode = RelativeSourceMode.Self } });
}
}
}

然后在 Style 中,使用

<Setter Property="local:BindingHelper.CommandParameterBinding" Value="True" />

会将 Button 设置为 CommandParameter。您的 Hamburger.xaml 可能喜欢:

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Octopie.Styles">

<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Square.xaml" />
</ResourceDictionary.MergedDictionaries>

<Style x:Key="HamburgerStyle" TargetType="Button" BasedOn="{StaticResource SquareStyle}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Command">
<Setter.Value>
<local:ClickedCommand />
</Setter.Value>
</Setter>
<Setter Property="local:BindingHelper.CommandParameterBinding" Value="True" />
<Setter Property="Content" Value="&#xE700;" />
<Setter Property="FontFamily" Value="Segoe MDL2 Assets" />
</Style>
</ResourceDictionary>

我删除了 x:Class="Octopie.Styles.Hamburger" 和 Hamburger.xaml.cs,因为您的 ResourceDictionary 不需要使用代码隐藏。

现在我们可以像这样在我们的页面中使用这个ResourceDictionary:

<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Hamburger.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<SplitView DisplayMode="CompactOverlay" IsPaneOpen="True">
<SplitView.Pane>
<StackPanel>
<Button Style="{StaticResource HamburgerStyle}" />
</StackPanel>
</SplitView.Pane>
</SplitView>
</Grid>

但是ClickedCommandExecute方法还有一个问题。在此方法中,您使用了 FrameworkElement.Parent检索 SplitView。但是

Parent can be null if an object was instantiated, but is not attached to an object that eventually connects to a page object root.

Most of the time, Parent is the same value as returned by VisualTreeHelper APIs. However, there may be cases where Parent reports a different parent than VisualTreeHelper does.

在您的情况下,您需要使用 VisualTreeHelper.GetParent 来获取 SplitView。我们可以使用辅助方法来执行此操作:

public static T FindParent<T>(DependencyObject child) where T : DependencyObject
{
//get parent item
DependencyObject parentObject = VisualTreeHelper.GetParent(child);

//we've reached the end of the tree
if (parentObject == null) return null;

//check if the parent matches the type we're looking for
T parent = parentObject as T;
if (parent != null)
return parent;
else
return FindParent<T>(parentObject);
}

然后在 Execute 方法中使用:

public void Execute(object parameter)
{
var button = (Button)parameter;
var splitView = FindParent<SplitView>(button);
splitView.IsPaneOpen = !splitView.IsPaneOpen;
}

现在 HamburgerStyle 将按照您的意愿工作。

关于c# - 如何从 ResourceDictionary 设置 Button.Command?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35052115/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com