有没有办法在WPF中重用绑定?

7
我正在开发一款WPF应用程序,现在到了控件上所有绑定变得非常重复和冗长的地步。如果我想要更改这个绑定,我必须在各个地方进行修改,而不是只需修改一次。
是否有一种方法可以将绑定的源部分写在资源中,并通过更紧凑的语法引用它以重用它呢?我已经搜索了这样的功能,但没有找到。 我现在的做法
<StackPanel>
    <ToggleButton x:Name="someToggleButton" />
    <Button Visibility="{Binding ElementName=someToggleButton, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}}" />
    <Grid Visibility="{Binding ElementName=someToggleButton, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}}" />
    <TextBox Visibility="{Binding ElementName=someToggleButton, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}}" />
    <CheckBox Visibility="{Binding ElementName=someToggleButton, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}}" />
</StackPanel>

我想要实现的功能(伪代码)

<StackPanel>
    <StackPanel.Resources>
        <Variable x:Name="someToggleButtonIsChecked" 
                  Type="{x:Type Visibility}"  
                  Value="{Binding ElementName=someToggleButton, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}}" />
    </StackPanel.Resources>

    <ToggleButton x:Name="someToggleButton" />
    <Button Visibility="{VariableBinding someToggleButtonIsChecked}" />
    <Grid Visibility="{VariableBinding someToggleButtonIsChecked}" />
    <TextBox Visibility="{VariableBinding someToggleButtonIsChecked}" />
    <CheckBox Visibility="{VariableBinding someToggleButtonIsChecked}" />
</StackPanel>

有没有类似的特性或技术可以让我声明绑定源一次,然后重复使用它呢?
3个回答

1
你可以将someToggleButtonIsChecked属性绑定到视图模型(DataContext)上的一个属性,然后使用它。代码如下:
<StackPanel>  
<ToggleButton x:Name="someToggleButton" IsChecked="{Binding ToggleVisibility, Mode=TwoWay, Converter={StaticResource BoolToVisibilityConverter}}"   /> 
<Button Visibility="{Binding ToggleVisibility}" /> 
<Grid Visibility="{Binding ToggleVisibility}" /> 
<TextBox Visibility="{Binding ToggleVisibility}" /> 
<CheckBox Visibility="{Binding ToggleVisibility}" /> 
</StackPanel> 

这将需要您的WindowDataContext具有名为ToggleVisibility的类型为Visibility的属性。

编辑:

进一步阐述,您的视图模型可能如下所示:

public class SomeViewModel : INotifyPropertyChanged
{

    private Visibility toggleVisibility;

    public SomeViewModel()
    {
        this.toggleVisibility = Visibility.Visible;
    }

    public Visibility ToggleVisibility
    {
        get
        {
            return this.toggleVisibility;
        }
        set
        {
            this.toggleVisibility = value;
            RaisePropertyChanged("ToggleVisibility");
        }
    }

    private void RaisePropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

然后您可以将其实例设置为Window甚至只是StackPanel上的DataContext


这实际上与我最初的方式相似,但是要添加到我的代码后台中的代码有点多,仅用于一个属性。从长远来看,如果没有基于XAML的解决方案,我可能会重新回到更像MVVM的方式。 - jpierson
@Jpierson,你真的应该回到使用MVVM。我的意思是,你已经有一个文本框,你可以将其值绑定到视图模型,还有一个按钮,你也可以将其命令绑定到视图模型。在我看来,视图模型是正确的选择,而在窗口中编写代码则不是。 - Klaus Byskov Pedersen
我目前在我的主代码中使用ViewModels,但这段代码在一个小对话框中,添加一个ViewModel似乎是不必要的,因为真正没有“Model”来支持我的ViewModel。同时我遇到的另一个问题是,在控件的绑定中需要链接一个BoolToVisibilityConverter和一个InverseBoolConverter。在我的代码后台或ViewModel中创建一个名为IsNotDeleteMode的属性可能会起作用,但是我还需要IsAddMode、IsNotAddMode、IsDeleteMode和IsNotDeleteMode属性。无论它放在哪里,这似乎都很混乱。 - jpierson
顺便提一下,串联/管道化ValueConverters的想法是我开始意识到相应的绑定声明会相对于其余的XAML变得困难,因此正在寻找重用这种绑定的解决方案。因此,即使我使用了ViewModel,除非我想编写我在最后一条评论中列出的所有否定属性形式,否则我仍然需要一种更可重用的技术来声明绑定。 - jpierson
在以下网址上找到了解决反向布尔属性多重性的方法(请参见leblancmeneses发布的帖子)。但我仍然想知道是否还有其他重用绑定声明的方法,否则我将研究使用标记扩展的自定义解决方案。 http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/f2154f63-ccb5-4d6d-8c01-81f9da9ab347/ - jpierson

0
有没有办法将绑定的源部分写成资源,然后通过更紧凑的语法引用它以便重复使用?
也许您可以使用PyBinding来实现这一点。我不知道它的能力范围,但我经常使用它来避免类型转换。以下是我经常使用的一个示例。
Visibility="{p:PyBinding BooleanToVisibility(IsNotNull($[.InstanceName]))}"
  • BooleanToVisibility是我在IronPython中编写的一个函数。
  • $[.InstanceName]绑定到当前数据绑定项的InstanceName属性。

EDIT: 您还可以使用此功能将一个UI的属性绑定到另一个UI的属性。以下是帮助文件中的一些信息。

  • $ [NameTextBlock.Text] - x:Name等于“NameTextBlock”的元素的文本属性
  • $ [NameTextBlock] - 实际的TextBlock实例,而不是其属性之一
  • $ [{Self}] - 绑定到您自己。等效于{Binding RelativeSource = {RelativeSource Self}}
  • $ [{Self}.Text] - 您自己的Text属性。等效于{Binding Path = Text,RelativeSource = {RelativeSource Self}}

http://pybinding.codeplex.com/

未经测试的理论

<StackPanel> 
    <ToggleButton x:Name="someToggleButton" /> 
    <Button Visibility="{p:PyBinding BooleanToVisibility($[someToggleButton.IsChecked])}" /> 
    <Grid Visibility="{p:PyBinding BooleanToVisibility($[someToggleButton.IsChecked])}"/> 
    <TextBox Visibility="{p:PyBinding BooleanToVisibility($[someToggleButton.IsChecked])}"/> 
    <CheckBox Visibility="{p:PyBinding BooleanToVisibility($[someToggleButton.IsChecked])}"/> 
</StackPanel> 

第二次尝试

<StackPanel> 
    <ToggleButton x:Name="someToggleButton" /> 
    <Button Name="myButton" Visibility="{p:PyBinding BooleanToVisibility($[someToggleButton.IsChecked])}" /> 
    <Grid Visibility="{p:PyBinding $[myButton.Visibility]}"/> 
    <TextBox Visibility="{p:PyBinding $[myButton.Visibility]}"/> 
    <CheckBox Visibility="{p:PyBinding $[myButton.Visibility]}"/> 
</StackPanel> 

这很不错,而且是我不知道的东西。但是这种方法的问题在于,我实际上想要将绑定存储在一个地方。例如,假设我想要在某个时候修改所有这些控件的可见性,以便由ToggleButton.IsEnabled属性驱动。我将不得不在多个地方进行更改,这就是为什么我有兴趣声明一次并重复使用它的原因。 - jpierson
你可以给按钮命名,然后将所有其他控件的可见性绑定到它上面。我知道这不完全是你想要的,但它更接近了。 - Jonathan Allen
是的,我也做过这个。如果再进一步,我可以创建一个通用的自定义控件,只有一个名为Value(MyBindingControl<T>)的属性。然后,对于每种要重复使用绑定的类型,我可以制作一个专门的类,例如StringBindingControl:MyBindingControl<string>。这可以用作其他控件可以绑定到的变量。这种技术的主要问题是,在资源字典中的通用样式/模板中难以重用,因为它很可能依赖于命名控件。 - jpierson

0

仅查看原始代码,您可以将必要的元素分组到自己的容器中,然后管理容器的可见性:

<StackPanel>
    <ToggleButton x:Name="someToggleButton" />
    <StackPanel Visibility="{Binding ElementName=someToggleButton, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}}">
        <Button />
        <Grid />
        <TextBox />
        <CheckBox />
    </StackPanel>
</StackPanel>

其实,今天我会使用VSM来完成这个任务——创建一个状态,其中包含可见元素和不可见元素,然后在切换按钮上使用两个GoToState行为,根据按钮的切换状态设置状态。

1
不错的观点,然而这段代码只是为了演示一般情况下重复使用绑定的愿望。有些情况下,被绑定的元素可能并不整齐地位于单个容器中的同级位置。 - jpierson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接