2015-02-09 23 views
0

编辑:我找到了一个重现问题的最简单方法。开始在Visual Studio中的一个新的Windows Phone应用程序模板,并将其加入到您的MainPage.xamlWindows Phone:在C#中应用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平方米;你只能通过点击它来告诉它。第二种风格是BasedOn,它显示white_circle.png代替空白方块。在我的代码隐藏的C#文件中,我有两种使用这些样式的方法:一种是在页面加载时调用,另一种在单击按钮时调用。

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 

当用户第一次导航到页面时,这些按钮都是黑色的,并且它们应该是不可见的。白色圆圈按预期出现在空间中。但是,当它从现场消失时,圆形会留下未应用任何样式的按钮。 (见图片)。

buttons

+0

您应该也可以在'TileStyle'中为'Template'属性设置一个Setter。 – Clemens 2015-02-09 08:25:35

+1

其实,你没有附加任何图像到你的文章。就实际问题而言,您需要发布[a _minimal_,_complete_代码示例](http://stackoverflow.com/help/mcve)。我根据你发布的内容写了一个简单的例子,它对我来说工作得很好。我只需设置一个计时器,通过按钮循环,每次设置一个具有'CircleStyle'风格,并将之前设置的一个设置回''TileStyle'',而不是处理鼠标点击。即使重新设置为“TileStyle”,该按钮仍保持空白,并且看起来不像普通按钮。 – 2015-02-09 09:46:03

+0

你能告诉我们你的'TileStyle'属性的代码吗? – 2015-02-09 14:52:10

回答

1

谢谢你提供的最小的摄制情况。这使得解释发生的事情变得非常容易(至少在这种情况下......人们希望你的真实世界的场景实际上是相似的,而且看起来很可能)。

问题源于您使用x:Name而不是x:Key作为您的样式资源。在这种情况下,它不会做你认为或希望它做的事情。特别是,虽然编译器基于指定的x:Name值创建了名为​​的字段,并且XAML编译器允许使用x:Name代替x:Key指定的正确密钥,但两者不连接。

用于检索​​字段的值的编译器生成的代码使用与资源字典不兼容的机制,即它调用FindName()方法,传递您提供的名称。但该方法用于在FrameworkElement的对象图中查找命名对象;它不会(也不打算)在资源字典中查找对象。

基本上,编译器看到x:Name并愉快地发出它的样板来实现支持元素的字段。只是盲目遵循执行x:Name的规则,结果不适用于资源。

那么当您拨打FindName(),传递一个不存在的名字时会发生什么?它返回null。所以​​字段得到(或者说保持,因为这是默认值)的值为null

当您将Button对象的Style属性设置为null时会发生什么?它只是将所有内容重置为默认值! Button最初看起来很好(在您的实际场景中),因为{StaticResource TileStyle}语法是处理资源的正确语法,允许x:Name替代资源x:Key属性。

在最小的repro示例中,最直接的修复方法是正确初始化资源(使用x:Name语法适用于基于特定Storyboard的情况,通常不是正确的方法),然后明确地实现你的​​领域:

<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属性应该正确地更新样式,而不是重置它。

这就是说,我不清楚,虽然上述显然是您的最小再现案例的解决方案,它将适用于您的现实世界的情况。特别是,在你的问题中,你声称将CircleStyle的值赋值给ButtonStyle属性确实是的工作。但假设CircleStyle字段的初始化与​​字段相同,但不清楚为什么这将起作用,而分配​​则不行。

I.e.我希望CircleStyle字段也是null,但它显然不可能是分配它确实将样式更改为您想要的。如果它不是null,那么为什么​​是null?但是,如果没有一个好的,最小的,完整的代码示例,那么就是的情况,我无法回答任何问题。


最后,我会注意到,可能有更好的方法来做到这一点,而不是在代码隐藏中硬编码样式。不幸的是,我对Phone API不够熟悉,不知道可能是什么。

在WPF中,我将使用StyleSelectorTrigger根据底层模型对象中的某些绑定属性更改对象外观。但经过相当长时间的实验后,我发现我对Phone API知之甚少,无法知道这些工作如何进行。 Trigger类似乎甚至不被支持,或者至少在Style.Triggers集合中不被允许,并且我结束了摔倒的兔子洞,试图找出如何在Phone中执行基于GridItemsControl(在WPF中,它不是很难,但是在绑定到Grid.RowGrid.Column附属属性时会涉及到一些小技巧,这些属性在手机中不起作用,因为显然手机不支持在样式的)中使用Binding

基本上,与WPF相比,基于XAML API的Silverlight/Phone/WinRT实现中缺少一个10吨。我之前使用WPF的经验对上述问题并没有多大帮助,因为WPF实现这些行为所依赖的很多功能在其他API中并不存在(微软的耻辱!)。

与此同时,我希望上述基于代码隐藏的方法能够解决您的特定问题。如果没有,那么你将需要发布一个更好的,但仍然最小和完整的代码示例。

相关问题