Подтвердить что ты не робот

WPF: прекратить привязку, если элемент пользовательского интерфейса не отображается

Можно ли привязать привязку элемента ui, если элемент в данный момент не отображается. Иногда у меня есть форма, в которой есть скрытые/минимизированные элементы, я бы не хотел их обновлять, если они не отображаются на экране. Я подозреваю, что ответ отрицательный, но никогда не больно спрашивать?

4b9b3361

Ответ 1

Нет встроенного способа сделать это, но вы можете написать его самостоятельно.

Трюк состоит в том, чтобы обернуть привязку в своем собственном расширении разметки, которое использует исходную привязку, но добавляет к ней новое поведение (например, установив UpdateSourceTrigger в Explicit, когда вы не хотите, чтобы привязка работала.

Вот пример (который задерживает передачу данных привязки):

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

Теперь существует множество возможных краевых условий с отключением привязок для невидимых элементов управления, особенно вокруг отображения и скрытия элементов управления, поэтому я бы не писал для этого общего расширения, но, возможно, в вашем конкретном приложении это может быть полезно.

Ответ 2

Ответ - нет, потому что привязка может быть причиной повторного создания элемента. Поэтому, если привязка не работает с скрытыми элементами управления, это не позволит привязке сделать ее видимой снова.

Ответ 3

Для обходного пути у меня есть привязка к видимости объекта, когда объект установлен на видимый, свойство запускает конструкцию элемента позади него, который имеет привязку через ContentPresenter.

Ответ 4

Я знаю, что это старый вопрос, но поскольку я не смог найти реализованный класс или что-то еще, я сделал это сам, следуя @Nir answer.

Это расширение разметки, которое обертывает нормальное связывание только на самом деле, когда свойство объекта 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}"/>

В этом примере он будет привязываться только тогда, когда ItemControl IsVisible станет истинным в первый раз.

Он не отменит, когда IsVisible снова получит ложь, но я думаю, что кто-то может изменить его по мере необходимости.

Ответ 5

Улучшена MarkupExtension, которая обертывает нормальную привязку для автоматической привязки/развязывания модели данных, если видимые изменения.
См. Предыдущую версию здесь.

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}"/>