2015-02-09 43 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中並不存在(微軟的恥辱!)。

與此同時,我希望上述基於代碼隱藏的方法能夠解決您的特定問題。如果沒有,那麼你將需要發佈一個更好的,但仍然最小和完整的代碼示例。

相關問題