3

Early start to the new year on SO for me :)

I'm trying to help out a friends with what I thought would be a simple thing. Basically we just want to change a style at runtime in code and update the style for a TextBlock.

I had no problem making this work with any other type of element, except the TextBlock. I'm now very curious if I've missed something here, or if indeed there is a bug. What would be the nicest way to solve this?

The code here is just for demonstration, it works with TextBox but not TextBlock (when targettype etc is changed of course)

Style defined in a resourcedictionary called StandardStyles, under the Common folder

    <Style x:Key="textStyle" TargetType="TextBlock">
    <Setter Property="Foreground" Value="red"/>
    <Setter Property="FontFamily" Value="Segoe UI"/>
</Style>

The UI

    <StackPanel Orientation="Horizontal">
    <ListBox ItemsSource="{Binding Fonts}" Height="300" Width="300" SelectionChanged="ListBox_SelectionChanged_1"></ListBox>
    <Border BorderBrush="White" BorderThickness="5" Padding="20,0,0,0" Height="300" Width="300">
        <TextBlock Text="Hi here is some text" Style="{Binding FontStyleText}"/>
    </Border>
</StackPanel>

The code

    public sealed partial class MainPage : INotifyPropertyChanged 
{
    private Style _fontStyleText;
    public Style FontStyleText
    {
        get
        {
            return this._fontStyleText;
        }

        set
        {
            if (value == this._fontStyleText) return;
            this._fontStyleText = value;
            NotifyPropertyChanged();
        }
    }

    private List<string> _fonts;
    public List<string> Fonts
    {
        get
        {
            return this._fonts;
        }

        set
        {
            if (value == this._fonts) return;
            this._fonts = value;
            NotifyPropertyChanged();
        }
    }


    public MainPage()
    {
        this.InitializeComponent();
        DataContext = this;

        Fonts = new List<string> {"Segoe UI", "Showcard Gothic", "Arial"};

        FontStyleText = Application.Current.Resources["textStyle"] as Style;

    }

    private void ListBox_SelectionChanged_1(object sender, Windows.UI.Xaml.Controls.SelectionChangedEventArgs e)
    {
        var font = (sender as ListBox).SelectedItem as string;

        var res = new ResourceDictionary()
        {
            Source = new Uri("ms-appx:///Common/StandardStyles.xaml", UriKind.Absolute)
        };

        var style = res["textStyle"] as Style;

        style.Setters.RemoveAt(0); // if it is the first item otherwise for more accurat removal se below :D


        foreach (var item in style.Setters.Cast<Setter>().Where(item => item.Property == FontFamilyProperty))
        {
            style.Setters.Remove(item);
        }

        style.Setters.Add(new Setter(FontFamilyProperty, new FontFamily(font)));
        style.Setters.Add(new Setter(ForegroundProperty, new SolidColorBrush(Colors.Purple)));

        FontStyleText = style;

    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
4

6 回答 6

1

好的,所以我弄清楚出了什么问题。

非常感谢 mlorbetske (以及 Skype 上的 Matt),我注意到我在这段代码中遗漏了一些东西。是的,很高兴地说这不是一个错误,而是(大多数时候)缺少一些东西。我会说没有收到错误消息是一个错误。

我缺少正确的依赖属性 - 目标属性设置错误。所以而不是:

style.Setters.Add(new Setter(FontFamilyProperty, new FontFamily(font)));

我不得不

style.Setters.Add(new Setter(TextBlock.FontFamilyProperty, new FontFamily(font)));

而已 :)

于 2013-01-02T19:27:22.730 回答
1

尝试将ListBox_SelectionChanged_1方法更改为如下所示。无论出于何种原因,在将设置添加到样式的设置器时似乎都会抛出一个静默错误FontFamilyProperty- 或者至少在我切换事物以使用单独的视图模型时发生了错误。

    private void ListBox_SelectionChanged_1(object sender, Windows.UI.Xaml.Controls.SelectionChangedEventArgs e)
    {
        var font = (sender as ListBox).SelectedItem as string;

        var res = new ResourceDictionary()
        {
            Source = new Uri("ms-appx:///Common/StandardStyles.xaml", UriKind.Absolute)
        };

        var style = res["textStyle"] as Style;
        var newStyle = new Style(style.TargetType);

        foreach (var setter in style.Setters.OfType<Setter>().Skip(1).Where(x => x.Property != TextBlock.FontFamilyProperty))
        {
            newStyle.Setters.Add(new Setter(setter.Property, setter.Value));
        }

        newStyle.Setters.Add(new Setter(TextBlock.FontFamilyProperty, new FontFamily(font)));
        newStyle.Setters.Add(new Setter(TextBlock.ForegroundProperty, new SolidColorBrush(Colors.Purple)));

        FontStyleText = newStyle;
    }
于 2013-01-02T18:58:24.197 回答
1

它不起作用的原因之一是 TextBlock 在 StandardStyles.xaml 中定义了很多次。如果您可以创建一个新样式文档并在用户控件的 InitilizeComponent 之前应用它,它将起作用。希望这能解释。

于 2013-01-02T18:52:48.337 回答
0

以我的经验,我只使用过静态样式绑定,从未使用过动态的数据上下文。样式是通常在设计时创建并应用于多个项目以在整个应用程序中保持一致性的东西。

最好有一个样式,除了字体之外,你需要的所有东西都有一个正常的静态绑定,然后只绑定字体(按名称应该从内存中工作)以覆盖样式。

于 2013-01-02T18:13:03.747 回答
0

如果 TextBlock 的样式确实不适用于绑定 - 您可以简单地更新代码以将 TextBlock 放入 DataTemplate 中,并在样式更改时添加/替换您现在拥有 TextBlock 的模板的物化实例。

您还可以尝试添加 Style 类型的附加属性并将其更改传递给实际的 Style 属性。

于 2013-01-02T18:30:23.587 回答
0

Hm... I don't see a DataTrigger binding - should be under Style/Style.Triggers. You might want to try binding a trigger to your combo box - please take a look at the following links:

Style.Triggers Property - MSDN

CodeProject Example on Style DataTriggers for TextBlock

MSDN Question on binding a TextBlock style to a combo box change

Hope it helps.

Cheers,

Arthur

于 2013-01-02T19:03:27.370 回答