2010-02-10 23 views
17

如果元素當前不可見,是否可以延遲UI元素的綁定?有時候我有一個表單有一些隱藏/最小化的元素,如果他們不在屏幕上,我想不更新它們。我懷疑答案是否定的,但它從不傷害要問嗎?WPF:如果UI元素不可見,則停止綁定

+0

你爲什麼要這麼做?表現? – 2010-02-10 01:43:36

+0

是的表現,它的實際懶惰(懶惰是發明之母),因爲如果它們不可見,我應該從樹上移除東西,以獲得我需要的性能。 – 2010-02-10 02:22:26

回答

2

沒有內置的方法來做到這一點 - 但你可以自己寫。

訣竅是包裝在使用原來的約束力,但它周圍增加了新的行爲(例如,通過UpdateSourceTrigger設置爲Explicit自己的標記擴展綁定時你不希望綁定工作要做。

下面是一個例子(即延遲綁定的數據傳輸):

http://www.paulstovell.com/wpf-delaybinding

現在,有很多與禁用綁定無形的控制,尤其是在顯示和隱藏控制可能的邊界條件,所以我不會爲此寫一個通用的擴展 - 但可能在你的具體應用中,這可能是有用的。

+1

多數民衆贊成在奇怪的是,我寫了一個類似的東西 - http://www.codeproject.com/KB/WPF/DelayedBindingTextBox.aspx – 2010-02-16 05:39:36

7

答案是否定的,因爲綁定可能是導致元素再次可見的原因。因此,如果綁定不能在隱藏的控件上工作,它將不允許綁定再次使其可見。

2

解決方法我有一個綁定到對象的可見性,當對象設置爲可見時,該屬性觸發通過ContentPresenter具有綁定後面的元素的構造。

2

我知道這是一個古老的問題,但由於我沒有找到實現的類或其他東西,我自己做了,遵循@Nir的答案。

這是一個標記擴展,它包裝正常結合到當對象IsVisible屬性首次變爲真才真正地結合:

using System; 
using System.ComponentModel; 
using System.Globalization; 
using System.Windows; 
using System.Windows.Data; 
using System.Windows.Markup; 

namespace MakupExtensions { 
    [MarkupExtensionReturnType(typeof(object))] 
    public class LazyBindingExtension : MarkupExtension { 
     public LazyBindingExtension() { 
     } 
     public LazyBindingExtension(PropertyPath path) : this() { 
      Path = path; 
     } 

     public IValueConverter Converter { 
      get; 
      set; 
     } 
     [TypeConverter(typeof(CultureInfoIetfLanguageTagConverter))] 
     public CultureInfo ConverterCulture { 
      get; 
      set; 
     } 
     public object ConverterParamter { 
      get; 
      set; 
     } 
     public string ElementName { 
      get; 
      set; 
     } 
     [ConstructorArgument("path")] 
     public PropertyPath Path { 
      get; 
      set; 
     } 
     public RelativeSource RelativeSource { 
      get; 
      set; 
     } 
     public object Source { 
      get; 
      set; 
     } 
     public UpdateSourceTrigger UpdateSourceTrigger { 
      get; 
      set; 
     } 
     public bool ValidatesOnDataErrors { 
      get; 
      set; 
     } 
     public bool ValidatesOnExceptions { 
      get; 
      set; 
     } 
     public bool ValidatesOnNotifyDataErrors { 
      get; 
      set; 
     } 

     private Binding binding; 
     private DependencyObject bindingTarget; 
     private DependencyProperty bindingTargetProperty; 

     public override object ProvideValue(IServiceProvider serviceProvider) { 
      var valueProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget; 
      if (valueProvider != null) { 
       bindingTarget = valueProvider.TargetObject as DependencyObject; 
       bindingTargetProperty = valueProvider.TargetProperty as DependencyProperty; 
       if (bindingTargetProperty == null || bindingTarget == null) { 
        throw new NotSupportedException($"The property '{valueProvider.TargetProperty}' on target '{valueProvider.TargetObject}' is not valid for a LazyBinding. The LazyBinding target must be a DependencyObject, and the target property must be a DependencyProperty."); 
       } 
       binding = new Binding { 
        Path = Path, 
        Converter = Converter, 
        ConverterCulture = ConverterCulture, 
        ConverterParameter = ConverterParamter 
       }; 
       if (ElementName != null) { 
        binding.ElementName = ElementName; 
       } 
       if (RelativeSource != null) { 
        binding.RelativeSource = RelativeSource; 
       } 
       if (Source != null) { 
        binding.Source = Source; 
       } 
       binding.UpdateSourceTrigger = UpdateSourceTrigger; 
       binding.ValidatesOnDataErrors = ValidatesOnDataErrors; 
       binding.ValidatesOnExceptions = ValidatesOnExceptions; 
       binding.ValidatesOnNotifyDataErrors = ValidatesOnNotifyDataErrors; 
       return SetBinding(); 
      } 
      return null; 
     } 
     public object SetBinding() { 
      var uiElement = bindingTarget as UIElement; 
      if (uiElement != null && !uiElement.IsVisible) { 
       uiElement.IsVisibleChanged += UiElement_IsVisibleChanged; 
      } 
      else { 
       ConsolidateBinding(); 
      } 
      return bindingTarget.GetValue(bindingTargetProperty); 
     } 
     private void ConsolidateBinding() => BindingOperations.SetBinding(bindingTarget, bindingTargetProperty, binding); 
     private void UiElement_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { 
      var uiElement = sender as UIElement; 
      if (uiElement != null && uiElement.IsVisible) { 
       uiElement.IsVisibleChanged -= UiElement_IsVisibleChanged; 
       ConsolidateBinding(); 
      } 
     } 
    } 
} 

要使用:

<ItemsControl ItemsSource="{mx:LazyBinding Documents}"/> 

在這個例子中,它只會在ItemsControl IsVisible第一次變爲true時綁定。

IsVisible再次失敗時,它不會解除綁定,但我認爲有人可以根據需要進行更改。

0

改進的MarkupExtension包裝普通的綁定,以在可見變化時自動綁定/取消綁定數據模型。
參見以前的版本here

using System; 
using System.ComponentModel; 
using System.Globalization; 
using System.Windows; 
using System.Windows.Data; 
using System.Windows.Markup; 

namespace UtilsWPF 
{ 
    [MarkupExtensionReturnType(typeof(object))] 
    public class LazyBindingExtension : MarkupExtension 
    { 
     public LazyBindingExtension() 
     { } 

     public LazyBindingExtension(PropertyPath path) : this() 
     { 
      Path = path; 
     } 

     #region Properties 

     public IValueConverter Converter { get; set; } 
     [TypeConverter(typeof(CultureInfoIetfLanguageTagConverter))] 
     public CultureInfo ConverterCulture { get; set; } 
     public object ConverterParamter { get; set; } 
     public string ElementName { get; set; } 
     [ConstructorArgument("path")] 
     public PropertyPath Path { get; set; } 
     public RelativeSource RelativeSource { get; set; } 
     public object Source { get; set; } 
     public UpdateSourceTrigger UpdateSourceTrigger { get; set; } 
     public bool ValidatesOnDataErrors { get; set; } 
     public bool ValidatesOnExceptions { get; set; } 
     public bool ValidatesOnNotifyDataErrors { get; set; } 

     private Binding binding; 
     private UIElement bindingTarget; 
     private DependencyProperty bindingTargetProperty; 

     #endregion 

     #region Init 

     public override object ProvideValue(IServiceProvider serviceProvider) 
     { 
      var valueProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget; 
      if (valueProvider != null) 
      { 
       bindingTarget = valueProvider.TargetObject as UIElement; 

       if (bindingTarget == null) 
       { 
        throw new NotSupportedException($"Target '{valueProvider.TargetObject}' is not valid for a LazyBinding. The LazyBinding target must be a UIElement."); 
       } 

       bindingTargetProperty = valueProvider.TargetProperty as DependencyProperty; 

       if (bindingTargetProperty == null) 
       { 
        throw new NotSupportedException($"The property '{valueProvider.TargetProperty}' is not valid for a LazyBinding. The LazyBinding target property must be a DependencyProperty."); 
       } 

       binding = new Binding 
       { 
        Path = Path, 
        Converter = Converter, 
        ConverterCulture = ConverterCulture, 
        ConverterParameter = ConverterParamter 
       }; 

       if (ElementName != null) 
       { 
        binding.ElementName = ElementName; 
       } 

       if (RelativeSource != null) 
       { 
        binding.RelativeSource = RelativeSource; 
       } 

       if (Source != null) 
       { 
        binding.Source = Source; 
       } 

       binding.UpdateSourceTrigger = UpdateSourceTrigger; 
       binding.ValidatesOnDataErrors = ValidatesOnDataErrors; 
       binding.ValidatesOnExceptions = ValidatesOnExceptions; 
       binding.ValidatesOnNotifyDataErrors = ValidatesOnNotifyDataErrors; 

       return SetBinding(); 
      } 

      return null; 
     } 

     public object SetBinding() 
     { 
      bindingTarget.IsVisibleChanged += UiElement_IsVisibleChanged; 

      updateBinding(); 

      return bindingTarget.GetValue(bindingTargetProperty); 
     } 

     #endregion 

     #region Event Handlers 

     private void UiElement_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) 
     { 
      updateBinding(); 
     } 

     #endregion 

     #region Update Binding 

     private void updateBinding() 
     { 
      if (bindingTarget.IsVisible) 
      { 
       ConsolidateBinding(); 
      } 
      else 
      { 
       ClearBinding(); 
      } 
     } 

     private bool _isBind; 

     private void ConsolidateBinding() 
     { 
      if (_isBind) 
      { 
       return; 
      } 

      _isBind = true; 

      BindingOperations.SetBinding(bindingTarget, bindingTargetProperty, binding); 
     } 

     private void ClearBinding() 
     { 
      if (!_isBind) 
      { 
       return; 
      } 

      BindingOperations.ClearBinding(bindingTarget, bindingTargetProperty); 

      _isBind = false; 
     } 

     #endregion 
    } 
} 

要使用:

<ItemsControl ItemsSource="{utils:LazyBinding Documents}"/>