Можно ли привязать привязку элемента ui, если элемент в данный момент не отображается. Иногда у меня есть форма, в которой есть скрытые/минимизированные элементы, я бы не хотел их обновлять, если они не отображаются на экране. Я подозреваю, что ответ отрицательный, но никогда не больно спрашивать?
WPF: прекратить привязку, если элемент пользовательского интерфейса не отображается
Ответ 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}"/>