簡體   English   中英

Windows Phone:在C#中應用時,XAML樣式會“重置”自身

[英]Windows Phone: XAML Style 'resets' itself when applied in C#

編輯 :我已經找到了重現該問題的最小方法。 在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#文件中,我有兩種利用這些樣式的方法:一種在Page加載時調用,另一種在單擊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

當用戶第一次導航到頁面時,按鈕全都是黑色的,因此應該是不可見的。 白色圓圈將按預期出現在空間中。 但是,當它從該點消失時,該圓會留在沒有應用樣式的Button后面。 (參見圖片。)

紐扣

感謝您提供最少的復制情況。 這樣就很容易解釋發生了什么(嗯,至少在那種情況下……人們希望您的現實情況實際上是相似的,而且這確實有可能)。

問題源於您為樣式資源使用x:Name而不是x:Key 在這種情況下,它不會按照您的想法或希望做。 特別是,盡管編譯器確實根據資源的指定x:Name值創建了名為TileStyle的字段,而XAML編譯器允許使用x:Name代替x:Key指定的適當鍵, TileStyle兩個不要連接。

編譯器生成的用於檢索TileStyle字段的值的代碼使用與資源字典不兼容的機制,即,它將調用FindName()方法,並傳遞您提供的名稱。 但是該方法用於在FrameworkElement的對象圖中查找已命名的對象。 它不會(也不打算)在資源字典中查找對象。

基本上,編譯器看到x:Name並愉快地發出其樣板,以實現支持元素的字段。 它只是盲目地遵循實現x:Name的規則,事實證明這不適用於資源。

那么,當您調用FindName()並傳遞不存在的名稱時會發生什么呢? 返回null 因此, TileStyle字段獲得(或保持TileStyle ,因為這是默認值)的null

當將Button對象的Style屬性設置為null時會發生什么? 它只是將所有內容重置為默認值! 由於{StaticResource TileStyle}語法是處理資源的正確語法,並且允許使用x:Name替代資源x:Key屬性,因此Button最初看起來不錯(在您的實際情況下)。

在最小的復制示例中,最直接的解決方法是正確初始化資源(使用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.
    }
}

這樣,您現在應該為樣式字段提供非null值,並且將它們分配給Style屬性應該正確更新樣式,而不是將其重置。

就是說,我不清楚,雖然以上內容顯然是針對您的最小再現案例的解決方案,但它是否適用於您的實際情況。 特別是,在您的問題中,您聲稱將CircleStyle的值分配給ButtonStyle屬性確實有效。 但是,假設CircleStyle字段的初始化方式與TileStyle字段相同,則不清楚為什么在分配TileStyle不會TileStyle

也就是說,我希望CircleStyle字段也為null ,但是如果分配確實將樣式更改為您想要的樣式,則顯然不能為null 如果它不為null ,那么為什么TileStylenull 但是,如果沒有一個很好的,最小的,完整的代碼示例來精確解決問題,我將無法回答任何有關此的問題。


最后,我將指出,這樣做可能比在后面的代碼中硬編碼樣式更好。 不幸的是,我對Phone API不夠熟悉,無法知道可能是什么。

在WPF中,我將使用StyleSelectorTrigger基於基礎模型對象中的某些綁定屬性來更改對象外觀。 但是經過大量的時間試驗后,我發現我對Phone API的了解還不夠多,無法知道它們將如何工作。 Style.Triggers集合中似乎甚至不支持Trigger類,或者至少不允許使用該Trigger類,並且我最終掉下了兔子洞,試圖弄清楚如何在Phone中使用基於GridItemsControl (在WPF中)這並不難,但是綁定到Grid.RowGrid.Column附加屬性有一些技巧,這些屬性在Phone中不起作用,因為顯然Phone不支持在樣式的SetterValue屬性中使用Binding

基本上,有一從Silverlight的/電話/ WinRT的實施基於XAML的API的缺失,相比WPF。 我以前使用WPF的經驗並不能幫助我解決上述問題,因為我在WPF中依賴於實現這些行為的很多功能只是其他API中不存在(對Microsoft感到羞恥!)。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM