2010-02-10 15 views
17

Czy mogę opóźnić wiązanie elementu interfejsu użytkownika, jeśli element nie jest obecnie widoczny. Czasami mam formularz, który ma jakieś ukryte/zminimalizowane elementy, nie chciałbym ich aktualizować, jeśli nie ma ich na ekranie. Podejrzewam, że odpowiedź brzmi nie, ale nigdy nie boli zapytać?WPF: Zatrzymaj wiązanie, jeśli element interfejsu nie jest widoczny.

+0

dlaczego chcesz to zrobić? dla wydajności? –

+0

tak wydajność, to faktycznie lenistwo (lenistwo jest matką wynalazku), ponieważ powinienem usuwać rzeczy z drzewa, jeśli nie są one widoczne, aby uzyskać wydajność, której potrzebuję. –

Odpowiedz

2

Nie ma wbudowanego sposobu, aby to zrobić - ale możesz napisać to sam.

Sztuką jest owinąć wiązania w swoim własnym rozszerzeniem znaczników, który wykorzystuje oryginalne wiązania ale dodaje nowe zachowanie wokół niego (na przykład poprzez ustawienie UpdateSourceTrigger do Explicit gdy nie chcesz wiązanie do pracy.

Oto przykład (który opóźnia wiązanie znajduje transfer danych):

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

teraz istnieje wiele możliwych warunków brzegowych o wyłączenie wiązań dla niewidzialnych kontroli, zwłaszcza wokół pokazując i ukrywając kontroli, więc nie będę Napisz ogólne rozszerzenie dla tego - ale może być w konkretnej aplikacji może to być przydatne.

+1

to jest dziwne, napisałem coś podobnego - http://www.codeproject.com/KB/WPF/DelayedBindingTextBox.aspx –

7

Odpowiedź brzmi: nie, ponieważ powiązanie może być przyczyną ponownego uwidocznienia elementu. Jeśli więc wiązanie nie działało na ukrytych elementach sterujących, nie pozwoliłoby, aby wiązanie uczyniło je ponownie widocznym.

2

Aby obejść, mam powiązanie z widocznością obiektu, gdy obiekt jest ustawiony jako widoczny, właściwość uruchamia konstrukcję elementu, który ma wiązanie za pośrednictwem ContentPresenter.

2

Wiem, że to stare pytanie, ale ponieważ nie udało mi się znaleźć zaimplementowanej klasy lub czegoś takiego, zrobiłem to sam, po odpowiedzi @Nir.

To Markup Extension, który owija normalne wiązanie tylko naprawdę wiązać, gdy właściwość obiektu IsVisible staje się prawdą po raz pierwszy:

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(); 
      } 
     } 
    } 
} 

Sposób użycia:

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

W tym przykładzie, będzie wiązać tylko wtedy, gdy ItemsControl IsVisible stanie się prawdziwe po raz pierwszy.

Nie odłączy się, gdy IsVisible ponownie otrzyma wartość false, ale sądzę, że ktoś może ją zmienić w razie potrzeby.

0

Ulepszono rozszerzenie MarkupExtension, które zawija normalne powiązanie do modelu automatycznego wiązania/odrywania, jeśli widoczne jest zmienione.
Zobacz poprzednią wersję 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 
    } 
} 

Sposób użycia:

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