c# - 在 Windows 8.1 的 C# XAML 中,如何将样式绑定(bind)到变量?

标签 c# xaml windows-phone-8 syntax

我已经为这个问题苦苦挣扎了一段时间了,所以我想我应该在这里问一下,看看是否有人可以帮助我。首先,我是 C#、XAML 和 Windows 8 编程新手。

我想做的基本事情是:基于对数据模型的更改(我在 Button_Click 处理程序内的小测试床项目中执行此操作),我想更改 <Style> 中的前景值。我已成功更改 <TextBlock> 中的前景值,但未能成功更改在另一个 <Style> 上运行的 <TextBlock> 中的前景值。

这是我所做的(请原谅冗长,希望它有意义):

我有一个名为 MyColorDataSource 的类,我将其用作 MyPage.xaml 页面中的绑定(bind)目标。这是该类的相关代码:

public class MyColorDataSource 
{
    private MyColors _brush1;

    public MyColors Brush1
    {
        get { return _brush1; }
        set { _brush1 = value; }
    }

    private MyColors _brush2;

    public MyColors Brush2
    {
        get { return _brush2; }
        set { _brush2 = value; }
    }


    public MyColorDataSource()
    {
        _brush1 = new MyColors();
        _brush2 = new MyColors();

        _brush1.BrushColor= new SolidColorBrush(Colors.DarkRed);
        _brush2.BrushColor = new SolidColorBrush(Colors.Pink);
    }
}

您会注意到 MyColorDataSource 中的变量属于 MyColors 类型。这是该类的定义:

public class MyColors : INotifyPropertyChanged
{

    private SolidColorBrush _brushColor;

    public SolidColorBrush BrushColor
    {
        get { return _brushColor; }
        set {
            if (value != _brushColor)
            {
                _brushColor = value;
                NotifyPropertyChanged("BrushColor");
            }
        }
    }

    #region INotifyPropertyChanged Members

    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            Debug.WriteLine("in NotifyPropertyChanged for " + propertyName);
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

这是我编写的 XAML,其中有两个 <TextBlock> 元素,其中一个元素的 Foreground 属性直接绑定(bind)到数据源,其中一个元素使用我尝试绑定(bind)到数据源的 <Style>。在 MyPage.xaml 中:

<Page.Resources>
    <Style TargetType="TextBlock" x:Key="BoundColor">
        <Setter Property="Foreground" Value="{Binding Brush2.BrushColor}" />
    </Style>
</Page.Resources>
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <TextBlock x:Name="TextBlockToFormatWithBinding" Text="Direct Binding" Foreground="{Binding BrushColor}" />
    <TextBlock x:Name="TextBlockToFormatWithStyleBinding" Text="Binding through style" Style="{StaticResource BoundColor}"/>
</StackPanel>

我已在 App.xaml.cs 中设置了 DataSource 变量:

public sealed partial class App : Application
{

    public static MyColorDataSource ColorDataSource;

    public App()
    {
        this.InitializeComponent();
        this.Suspending += this.OnSuspending;

        ColorDataSource = new MyColorDataSource();
    }
}

我访问 MyPage.xaml.cs 中的数据源:

public MyPage()
{
    this.InitializeComponent();
    App.ColorDataSource.Brush1.BrushColor = new SolidColorBrush(Colors.DarkOliveGreen);
    App.ColorDataSource.Brush2.BrushColor = new SolidColorBrush(Colors.DarkKhaki);
    this.DataContext = App.ColorDataSource;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    TextBlockToFormatWithBinding.DataContext = App.ColorDataSource.Brush1;
    // TextBlockToFormatWithStyleBinding.DataContext = App.ColorDataSource.Brush2; // tried this, it did nothing
}

如果你还在我身边,谢谢你!发生的情况是,第一个 <TextBlock> 按预期显示,呈深橄榄绿颜色。第二个 <TextBlock> 根本不显示,我假设它的前景默认为黑色(页面背景也是黑色,所以我看不到它)。当我将 <Style> 中的前景值更改为“DarkRed”之类的值时,瞧,它按预期显示。所以 <TextBlock> 肯定存在,但它没有像我想要的那样从 DataModel 获取其前景值。

以前有人遇到过这个问题吗?如果有,你是如何解决的?我真的不想单独更改每个 <TextBlock> ,因为我打算尝试对 <ListView> 中的项目进行样式设置,而且我真的不想迭代所有 <Item> 并一一更改它们的样式。完成了大量的 HTML/CSS/jQuery 工作后,我习惯了能够按类来设置样式,而不是一次一个迭代地设置样式。

预先感谢您提供的任何帮助或建议。

编辑:

我确实设法遇到了一种技术,它使我非常接近我在这里尝试做的事情,部分是在下面的答案的帮助下(再次感谢!)。希望如果其他人也提出类似的问题,这会有所帮助。

    <SolidColorBrush x:Key="myBrush" Color="#330000FF" />
    <Style TargetType="TextBlock" x:Key="BoundColor">
        <Setter Property="Foreground" Value="{StaticResource myBrush}" />
    </Style>

然后在我的代码隐藏中,我可以做这样的事情:

((SolidColorBrush)Resources["myBrush"]).Color = Color.FromArgb(64, 255, 0, 0);

这本身并没有将元素的颜色放入数据模型中,但说实话,元素的颜色真的属于数据模型吗?我通常会说不是。

请注意,我没有任何运气使该技术在我尝试使用的“可见性”<Setter> 上工作(我希望 TextBlock 有时隐藏,有时可见),但对于颜色和其他基于对象的<Setter> s 它工作得很好。根据我所知的一点点,我的假设是这是真的,因为可见性是一个枚举,而不是类。因此,虽然我可以将其放入我的 <Page.Resources> 中:

    <Visibility x:Key="TextBlockVisibility">0</Visibility>

这在 <Style> 中:

    <Setter Property="Visibility" Value="{StaticResource TextBlockVisibility}" />

我似乎无法以 TextBlockVisibility 会注意到或受到值更改影响的方式更改 <Style> 的值。

最佳答案

抱歉,你不能。与许多非常有用的 WPF 功能一样(您的代码在 WPF 程序中运行得很好),据我所知,Windows Phone 不支持此功能。

也就是说,您可以解决这个问题。最明显的解决方案是首先不使用样式。另一种解决方案是使用“helper”对象作为样式中的实际 setter 值,该对象本身通过样式的 setter 设置的附加属性来管理绑定(bind)。

此技术的示例可以在 David Anson 的网站上找到: The taming of the phone [New SetterValueBindingHelper sample demonstrates its usefulness on Windows Phone 7 (and Silverlight 4)]

使用该示例,您的样式 setter 可能如下所示:

<Setter Property="delay:SetterValueBindingHelper.PropertyBinding">
  <Setter.Value>
    <delay:SetterValueBindingHelper
      Property="Foreground"
      Binding="{Binding Brush2.BrushColor}"/>
  </Setter.Value>
</Setter>

(注意:我实际上并没有测试您的代码的工作示例;您可能需要对绑定(bind)本身进行一些修改才能获得正确的数据上下文,因为我不确定它是否会正确地继承上下文具有额外间接的页面。)

关于c# - 在 Windows 8.1 的 C# XAML 中,如何将样式绑定(bind)到变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29570591/

相关文章:

c# - 带对象的全局静态类

c# - 如何应用TextBox控件模板?

wpf - 动态资源合并不将样式应用于第一个控件

windows-phone-8 - 在 Windows Phone 中拖动和重新排序列表框项目

windows - 在 Windows Phone 8 中映射点击事件/鼠标按下事件?

c# - 如何使用 TPL 数据流库指定无序执行 block ?

c# - 许多 DateTime 的比较速度更快

c# - 使用泛型委托(delegate)时如何理解逆变?

WPF StaticResource有效,DynamicResource无效

c# - 获取longlistselector中选中项的索引