【问题标题】:Any way to reuse Bindings in WPF?有什么方法可以在 WPF 中重用绑定?
【发布时间】:2011-01-09 13:28:33
【问题描述】:

在 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>

是否有任何类似的功能或技术可以让我声明一次绑定源然后重用它?

【问题讨论】:

    标签: wpf binding variables resources reusability


    【解决方案1】:

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

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

    实际上,今天我将使用 VSM 执行此操作 - 具有元素可见的状态和元素不可见的状态,然后在切换按钮上使用两个 GoToState 行为来根据按钮的切换状态设置状态。

    【讨论】:

    • 好点,但是创建此代码只是为了展示一般重用绑定的愿望。人们可能会发现绑定的元素在单个容器中没有整齐地定位为对等点。
    【解决方案2】:

    有什么方法可以将绑定的源部分写入一次,例如在资源中,然后通过使用更紧凑的语法引用它来重用它。

    也许你可以用 PyBinding 做到这一点。我不知道它的功能范围,但我一直使用它来避免类型转换器。这是一个我经常使用的例子。

    Visibility="{p:PyBinding BooleanToVisibility(IsNotNull($[.InstanceName]))}"
    
    • BooleanToVisibility 是我在 IronPython 中编写的一个函数。
    • $[.InstanceName] 绑定到当前数据绑定项的 InstanceName 属性。

    编辑:您还可以使用它来将一个 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 属性。我必须在多个地方更改它,这就是为什么我有兴趣声明一次然后重用它。
    • 您可以命名您的按钮,然后将所有其他控件的可见性绑定到它。我知道这不是你想要的,但它更接近。
    • 是的,我也这样做了。将其提升到另一个层次,我可以使用一个名为 Value (MyBindingControl) 的属性创建一个通用自定义控件。然后对于我想要重用绑定的每种类型,我可以创建一个专门的类,例如 StringBindingControl : MyBindingControl。然后可以将其用作一种变量,其他控件可以绑定到该变量。这种技术的主要问题是很难在资源字典中的通用样式/模板中重用,因为它很可能依赖于命名控件。
    【解决方案3】:

    您可以将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 上将它的一个实例设置为DataContext,甚至只是在StackPanel

    【讨论】:

    • 这实际上与我最初的相似,但它是相当多的代码添加到我的代码后面仅用于单个属性。从长远来看,如果没有基于 XAML 的解决方案,我可能会回归到更像 MVVM 的方式。
    • @Jpierson 你真的应该回到使用 MVVM。我的意思是您已经有一个文本框,您可以将其值绑定到视图模型,以及一个按钮,您也可以将其命令绑定到视图模型。在我看来,视图模型是正确的方法,而你的窗口中的代码不是。
    • 我目前在我的主代码中使用 ViewModel,但是这段代码在一个小对话框中,并且添加了一个 ViewModel 似乎没有必要,因为真的没有“模型”来支持我的 ViewModel。我同时遇到的另一个问题是,我需要在控件的绑定中链接 BoolToVisibilityConverter 和 InverseBoolConverter。通过在我的代码后面或 ViewModel 中创建一个属性,专门称为 IsNotDeleteMode 将起作用,但我有 IsAddMode、IsNotAddMode、IsDeleteMode 和 IsNotDeleteMode 属性。不管它去哪里,对我来说似乎都是一团糟。
    • 顺便说一句,链接/管道 ValueConverters 的想法是我开始发布的地方,即相对于 XAML 的其余部分,相应的 Binding 声明将开始变得不堪重负,因此正在寻找解决方案重用此类绑定。因此,即使我使用的是 ViewModel,除非我想编写我在上一条评论中列出的所有否定属性形式,否则我仍然认为需要一种更可重用的绑定声明技术。
    • 在以下 URL 找到了一个解决多重逆布尔属性的解决方案(参见 leblancmeneses 的帖子)。但是,我仍然想知道是否有任何其他方法可以重用绑定声明,否则我将研究使用标记扩展的自定义解决方案。 social.msdn.microsoft.com/Forums/en-US/wpf/thread/…
    猜你喜欢
    • 2010-11-24
    • 1970-01-01
    • 1970-01-01
    • 2015-11-02
    • 1970-01-01
    • 2011-01-15
    • 2015-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多