简体   繁体   English

如何在WPF中创建可重用的TextBlock绑定?

[英]How do I create a reusable TextBlock binding in WPF?

I've been teaching myself WPF and I'm still learning the basic concepts and terminology. 我一直在自学WPF,但仍在学习基本概念和术语。 So please forgive me if the title of this question isn't worded correctly. 因此,如果此问题的标题措词不正确,请原谅我。

I have the following XAML that's part of a HierarchicalDataTemplate bound to an object of type ViewModelBase : 我有以下XAML,它是绑定到ViewModelBase类型的对象的HierarchicalDataTemplate的一部分:

            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding PrefixStyle.Text}" 
                           FontWeight="{Binding PrefixStyle.Weight}" 
                           Foreground ="{Binding PrefixStyle.Foreground}" 
                           Margin="0,0,3,0"/>                                
                <TextBlock Text="{Binding ValueStyle.Text}" 
                           FontWeight="{Binding ValueStyle.Weight}" 
                           Foreground ="{Binding ValueStyle.Foreground}"
                           Margin="0,0,3,0"/>                     
                <TextBlock Text="{Binding SuffixStyle.Text}" 
                           FontWeight="{Binding SuffixStyle.Weight}" 
                           Foreground ="{Binding SuffixStyle.Foreground}" 
                           Margin="0,0,3,0"/>
                           ... 
            </StackPanel>

ViewModelBase has the corresponding properties referenced in the XAML: ViewModelBase具有XAML中引用的相应属性:

public TextBlockStyle PrefixStyle...
public TextBlockStyle ValueStyle...
public TextBlockStyle SuffixStyle... 


public class TextBlockStyle : INotifyPropertyChanged
{
    public string Text...
    public FontWieght Weight...
    public Brush Foreground 
}

How can I define the binding for TextBlock to TextBlockStyle only once in the XAML and save myself from having to explicitly bind each TextBlock property as above? 如何在XAML中只定义一次TextBlockTextBlockStyle的绑定,而不必像上面那样显式绑定每个TextBlock属性呢? So I can just have one line for each TextBlock : 所以我每个TextBlock只能一行:

                <StackPanel Orientation="Horizontal">
                    <TextBlock Source="{Binding PrefixStyle}" />                           
                    <TextBlock Source="{Binding ValueStyle}"  />                    
                    <TextBlock Source="{Binding SuffixStyle}" />
                 ...                                                              
                </StackPanel>

I just don't know where to start. 我只是不知道从哪里开始。 Do I need to subclass TextBlock? 我是否需要继承TextBlock? Use a BindingGroup? 使用BindingGroup?

This must be common issue programmers run into - so I apologize if this question has been asked before. 这肯定是程序员遇到的常见问题-因此,如果您以前曾问过这个问题,我深表歉意。 I've tried searching, but I'm so new to WPF I don't know how to properly express my question. 我已经尝试过搜索,但是我对WPF还是陌生的,我不知道如何正确表达我的问题。

You use implicit styling to set a "global" style across your application. 您可以使用隐式样式在整个应用程序中设置“全局”样式。 This is usually done in your App.xaml file inside of the ResourceDictionary . 这通常是在ResourceDictionary内部的App.xaml文件中完成的。

<Style TargetType="{x:Type TextBlock}"
       BasedOn="{StaticResource TextBlockStyle}">
    <Setter Property="FontWeight" 
            Value="Bold">
    </Setter>
    <Setter Property="Foreground" 
            Value="Red">
    </Setter>
</Style>

If you continue to use the method you're following (I wouldn't), you can change your setters to something like: 如果继续使用您要遵循的方法(我不会),则可以将设置方法更改为:

<Setter Property="FontWeight" 
        Value="{Binding Weight}">
</Setter>

Then, all of the TextBlock s in your application would use that style unless you define an explicit/implicit style more local to the control. 然后,应用程序中的所有TextBlock都将使用该样式,除非您定义了更本地化的显式/隐式样式。

Edit to elaborate the comments: 编辑以详细说明:

I am also using a TreeView and HierarchicalDataTemplate . 我也在使用TreeViewHierarchicalDataTemplate Thinking in MVVM fashion, each item in the TreeView (parent/child) should represent some sort of Model. 以MVVM方式思考, TreeView每个项(父项/子项)都应代表某种模型。 For instance, think of Windows Explorer. 例如,考虑一下Windows资源管理器。 Each item in it would be a Folder or Drive in MVVM world. 其中的每个项目在MVVM世界中都是FolderDrive Folder and Drive wouldn't have different font weight/color/size characteristics because that's all view related. FolderDrive不会具有不同的字体粗细/颜色/大小特征,因为这与所有视图相关。

In our example, you would have something like this: 在我们的示例中,您将具有以下内容:

public class BaseItem : ViewModel
{
    public ObservableCollection<BaseItem> Children { .... } 
    public bool IsSelected { .... }
    public string Title { .... } 
}

Since a folder can hold more folders, and a drive can holder folders you would something like: 由于一个文件夹可以容纳更多文件夹,而一个驱动器可以容纳文件夹,因此您将需要执行以下操作:

public class DriveVM : BaseItem { }
public class FolderVM : BaseItem { }

Which would all you to do Children.Add(new FolderVM(folder)); 您将全部由哪Children.Add(new FolderVM(folder));来做Children.Add(new FolderVM(folder)); inside of DriveVM , and that would show a folder under a drive. DriveVM内部,这将在驱动器下显示一个文件夹。 The problem is this can get pretty complex. 问题是这可能变得非常复杂。 In short though, I think inheritance is the key to using a TreeView . 简而言之,我认为继承是使用TreeView的关键。

Another option is something like this: 另一个选择是这样的:

<Style x:Name="PrefixTextBlockStyle"
       TargetType="{x:Type TextBox}">
    <Setter Property="FontWeight"
            Value="Bold" />
    <Setter Property="Foreground"
            Value="Red" />
    <Setter Property="Text"
            Value="{Binding Text}" 
    <Setter Property="Margin"
            Value="0 0 3 0" />
</Style>
<Style x:Name="SuffixTextBlockStyle"
       TargetType="{x:Type TextBox}">
    <Setter Property="FontWeight"
            Value="Italic" />
    <Setter Property="Foreground"
            Value="Orange" />
    <Setter Property="Text"
            Value="{Binding Text}" />
    <Setter Property="Margin"
            Value="0 0 3 0" />
</Style>

and then in your HierarchicalDataTemplate do: 然后在您的HierarchicalDataTemplate执行以下操作:

<StackPanel Orientation="Horizontal">
    <TextBlock DataContext="{Binding Prefix}"
               Style="{StaticResource PrefixTextBlockStyle} ">  
    ....                              
</StackPanel>
<StackPanel Orientation="Horizontal">
     <StackPanel.Resources>
         <Style TargetType="TextBlock">
              <Setter Property="Text" Value="{Binding Text}" />
              <Setter Property="FontWeight" Value="{Binding Weight}" />
              <Setter Property="Foreground " Value="{Binding Foreground}" />
              <Setter Property="Margin" Value="0,0,3,0" />
         </Style>
     </StackPanel.Resources>

     <TextBlock DataContext="{Binding PrefixStyle}"/>                                
     <TextBlock DataContext="{Binding ValueStyle}"/>                     
     <TextBlock DataContext="{Binding SuffixStyle}"/> 
      ... 
</StackPanel>

Or using a global named style in app.xaml: 或在app.xaml中使用全局命名样式:

<Application>
    <Application.Resources>
        <Style x:Key="MyTextBlockStyle" TargetType="TextBlock">
            <Setter Property="Text" Value="{Binding Text}" />
            <Setter Property="FontWeight" Value="{Binding Weight}" />
            <Setter Property="Foreground " Value="{Binding Foreground}" />
            <Setter Property="Margin" Value="0,0,3,0" />
        </Style>
    </Application.Resources>
</Application>

Usage elsewhere: 其他地方的用法:

<Window>
    <StackPanel>

    <!-- Single textblock with explicit style -->
    <TextBlock DataContext="Blah" Style="{StaticResource MyTextBlockStyle}" />

    <!-- Multiple textblocks with implicit style -->
    <StackPanel Orientation="Horizontal">
        <StackPanel.Resources>
            <Style TargetType="TextBlock" BasedOn={StaticResource MyTextBlockStyle}" />
        </StackPanel.Resources>

        <TextBlock DataContext="{Binding PrefixStyle}"/>                                
        <TextBlock DataContext="{Binding ValueStyle}"/>                     
        <TextBlock DataContext="{Binding SuffixStyle}"/> 
         ... 
    </StackPanel>
</Window>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM