WPF: Stop Binding if a UI element is not visible

后端 未结 5 477
滥情空心
滥情空心 2021-02-05 06:16

Can I delay binding of a ui element if the element is not currently visible. Sometimes I have a form that has some hidden/minimised elements, I would like to not update them if

相关标签:
5条回答
  • 2021-02-05 06:26

    The answer is no because the binding might be cause of making an element visible again. So if binding did not work on hidden controls it would not allow the binding to make it visible again.

    0 讨论(0)
  • 2021-02-05 06:32

    There is no built in way to do this - but you can write it yourself.

    The trick is to wrap binding in your own markup extension that uses the original binding but adds new behavior around it (for example, by setting UpdateSourceTrigger to Explicit when you don't want the binding to work.

    Here's an example (that delays the binding's data transfer):

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

    Now, there are a lot of possible edge conditions with disabling bindings for invisible controls, especially around showing and hiding controls, so I wouldn't write a generic extension for this - but maybe in your specific application this can be useful.

    0 讨论(0)
  • 2021-02-05 06:35

    For a workaround I have a binding to the visibility of the object, when the object is set to visible, the property triggers the construction of the element behind it which have a binding via a ContentPresenter.

    0 讨论(0)
  • 2021-02-05 06:36

    I know this is an old question, but as I failed to find an implemented class or something, I did it myself, following @Nir answer.

    This is a Markup Extension that wraps normal binding to only really bind when the object IsVisible property becomes true for the first time:

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

    To use:

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

    In this example, it will only bind when the ItemsControl IsVisible becomes true for the first time.

    It will not unbind when the IsVisible gets false again, but I think someone can change it as needed.

    0 讨论(0)
  • 2021-02-05 06:41

    Improved MarkupExtension that wraps normal Binding to auto bind/unbind data model if visible changed.
    See previous version 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
        }
    }
    

    To use:

    <ItemsControl ItemsSource="{utils:LazyBinding Documents}"/>
    
    0 讨论(0)
提交回复
热议问题