编辑:我找到了重现问题的最小方法。在Visual Studio中启动新的Windows Phone应用程序模板并将其添加到MainPage.xaml
:
<Page.Resources>
<Style x:Name="TileStyle" TargetType="Button">
<Setter Property="BorderThickness" Value="0,0,0,0" />
</Style>
</Page.Resources>
<Button x:Name="btn" Style="{StaticResource TileStyle}" />
这是你的代码隐藏文件(在OnNavigatedTo
事件处理程序中):
btn.Style = TileStyle;
导航到页面时重现问题。
原文:我正在尝试创建一个Windows Phone应用程序,它是Whack-A-Mole的最小版本。在我的游戏页面上,我有两个用XAML编写的按钮样式,代表一个被占用或未被占用的洞。
<Page.Resources>
<Style x:Name="TileStyle" TargetType="Button">
<Setter Property="BorderThickness" Value="0,0,0,0" />
<Setter Property="Width" Value="125"/>
<Setter Property="Height" Value="125" />
</Style>
<Style x:Name="CircleStyle" TargetType="Button"
BasedOn="{StaticResource TileStyle}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Rectangle Fill="{TemplateBinding Background}" />
<Image Source="/Assets/white_circle.png" />
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<!--later on...-->
<Grid>
<Button Style="{StaticResource TileStyle}" Click="Button_Click"/>
<Button Style="{StaticResource TileStyle}" Click="Button_Click"/>
<Button Style="{StaticResource TileStyle}" Click="Button_Click"/>
...
</Grid>
第一种风格基本上只是一个空白,黑色,125x125平方;你只能通过点击它来告诉它。第二种风格是基于那个,它显示一个white_circle.png来代替空白方块。
在我的代码隐藏C#文件中,我有两种利用这些样式的方法:一种是在页面加载时调用,另一种是在单击一个Button时调用。
protected async void OnNavigatedTo(NavigationEventArgs e)
while (!hasUserWonGame)
//sleeps for 1-3 secs
//decides where circle should go at by generating random int
b.Style = CircleStyle; //this works fine!
//more logic, waits
if (!hasUserWonRound)
b.Style = TileStyle; //reverts to TileStyle (this does not work!)
private void Button_Click(object sender, RoutedEventArgs e)
//decides if user is clicking on a circle
if (areTilesDisplayingCircle[index - 1])
//user has won the round!
hasUserWonRound = true;
b.Style = TileStyle; //this also does not work!
//more logic, updates score, decides if user has won the entire game
当用户首次导航到页面时,按钮都是黑色和不可见的,因为它们应该是。白色圆圈按预期出现在空间中。然而,当它从斑点消失时,圆圈留下一个没有应用样式的按钮。 (见图。)
答案 0 :(得分:1)
感谢您提供最小的repro案例。这样可以很容易地解释发生了什么(好吧,至少在这种情况下......人们希望你的真实场景实际上是相似的,这看起来很可能)。
问题源于您使用x:Name
代替x:Key
作为样式资源。在这种情况下,它不会按照您的想法或希望它做到。特别是,虽然编译器确实根据资源的指定TileStyle
值创建名为x:Name
的字段,而XAML编译器允许使用x:Name
代替正确的密钥由x:Key
指定,两者不连接。
用于检索TileStyle
字段的值的编译器生成的代码使用与资源字典不兼容的机制,即它调用FindName()
方法,传递您提供的名称。但是该方法用于在FrameworkElement
的对象图中查找命名对象;它不会(也不打算)在资源字典中查找对象。
基本上,编译器会看到x:Name
并愉快地发出其样板来实现支持元素的字段。它只是盲目地遵循实施x:Name
的规则,结果证明不适用于资源。
那么当你调用FindName()
,传递一个不存在的名字时会发生什么?它返回null
。因此,TileStyle
字段获取(或者更确切地说,因为这是默认设置)null
的值。
当您将Button
对象的Style
属性设置为null
时会发生什么?它只是将所有内容重置为默认值! Button
最初看起来很好(在您的实际场景中),因为{StaticResource TileStyle}
语法是处理资源的正确语法,并且x:Name
被允许替代资源x:Key
属性。
在最小的repro示例中,最直接的解决方法是正确初始化资源(x:Name
语法的使用是针对特定的基于Storyboard
的场景,通常不是正确的方法要做到这一点),然后明确实现您的TileStyle
字段:
<Page.Resources>
<Style x:Key="TileStyle" TargetType="Button">
<Setter Property="BorderThickness" Value="0,0,0,0" />
</Style>
</Page.Resources>
然后在您的代码隐藏中:
partial class MainPage : Page
{
private Style TileStyle;
public MainPage()
{
InitializeComponent();
TileStyle = (Style)this.Resources["TileStyle"];
// etc.
}
}
使用它,您现在应该为样式字段设置非空值,并将它们分配给Style
属性应该正确更新样式而不是重置它。
那就是说,我不清楚,虽然上面显然是你的最小repro案例的解决方案,但它将适用于你的真实场景。特别是,在您的问题中,您声称将CircleStyle
的值分配给Button
的{{1}}属性 可以正常工作。但假设Style
字段初始化与CircleStyle
字段相同,则不清楚为什么在分配TileStyle
时不起作用。
即。我希望TileStyle
字段也是CircleStyle
,但显然不能分配它确实将样式更改为您想要的样式。如果不是null
,那么为什么null
会TileStyle
?但是,如果没有一个能够精确解决 场景的优秀,最小,完整的代码示例,我无法回答任何问题。
最后,我要指出,有可能更好的方法来做到这一点,而不是硬编码代码隐藏中的样式。不幸的是,我对Phone API不太熟悉,不知道它可能是什么。
在WPF中,我将使用null
或StyleSelector
根据底层模型对象中的某些绑定属性更改对象外观。但是经过相当长的一段时间的实验,我发现我还不太了解Phone API,知道它们是如何工作的。 Trigger
类似乎甚至不被支持,或者至少不被允许在Trigger
集合中使用,并且我最终落入了一个兔子洞,试图找出如何做{{1}在Phone中基于Style.Triggers
(在WPF中并不难,但是在绑定到Grid
和ItemsControl
附加属性时有一点小技巧,这些属性在Phone中不起作用,因为显然手机不支持在样式Grid.Row
的{{1}}属性中使用Grid.Column
。
基本上,与WPF相比,基于XAML的API的Silverlight / Phone / WinRT实现中缺少 ton 。我以前使用WPF的经验对上述问题没有多大帮助,因为我在WPF中依赖于实现这些行为的大部分功能在其他API中都不存在(微软的耻辱!)。
与此同时,我希望上述基于代码隐藏的方法能够解决您的具体问题。如果没有,那么您需要发布一个更好但仍然是最小和完整的代码示例。