У меня есть привязка от переключателя, подключенного в коде позади. Я хочу привязать состояние isChecked от одной кнопки к 4 элементам управления видео, чтобы переключить функцию отключения звука. Я использую multibinding, чтобы привязать кнопку переключения к 4 различным элементам управления. Моя проблема заключается в использовании точек останова. Я вижу, что все запускается вплоть до свойства отключения звука для каждого объекта, но параметр свойства «значение» никогда не обновляется. Он остается в значении по умолчанию, когда создаются экземпляры элементов управления.
Итак, сначала я создаю привязки в коде позади
IMultiValueConverter converter = new EmptyMultiValueConverter();
MultiBinding myMultiBinding = new MultiBinding();
myMultiBinding.Converter = converter;
myMultiBinding.UpdateSourceTrigger = UpdateSourceTrigger.Default;
myMultiBinding.Mode = BindingMode.OneWayToSource;
myMultiBinding.NotifyOnSourceUpdated = true;
for (int i = 1; i < _maxNumberofPlayers; i++)
{
VideoPlayer player = new VideoPlayer()
{
Mute = false
};
myMultiBinding.Bindings.Add(new Binding("Mute") { Source = player
});
}
btnMuteToggle.SetBinding(SimpleButton.IsCheckedProperty, myMultiBinding);
Кажется, все это работает, потому что, когда я нажимаю кнопку, я вижу в многозначном преобразователе, что правильный статус кнопки isChecked достигает контрольных точек, в ConvertBack ниже я могу подтвердить, что значение является правильным логическим значением, которое отражает состояние кнопки переключения.
public class EmptyMultiValueConverter : IMultiValueConverter
{
#region IMultiValueConverter Members
public object Convert(object[] values, Type targetType, object
parameter, System.Globalization.CultureInfo culture)
{
// gets from the object source
return (bool)values[0];
}
public object[] ConvertBack(object value, Type[] targetTypes, object
parameter, System.Globalization.CultureInfo culture)
{
return new Object[] {value,value,value,value};
}
#endregion
}
На данный момент я могу подтвердить, что он попадает в свойство Mute и запускает SET 4 раза, но когда я прослеживаю его, параметр value остается в ранее установленном значении и не обновляется, чтобы отразить значение, переданное ему через ConvertBack
// mute property in the media player user control
public bool Mute
{
get { return _media.IsMuted; }
set
{
if (_media.IsMuted == value)
return;
else
{
_media.IsMuted = value;
NotifyPropertyChanged("Mute");
}
}
}
Может ли кто-нибудь помочь, пожалуйста. Рву на себе волосы уже 3 дня.
Мне показалось, что использование multibinding — это эффективный способ подключить 4 игрока с отдельными элементами управления и привязать их к одному нажатию кнопки.
Я пытаюсь заставить мультипривязки работать, чтобы щелкнуть одну кнопку переключения и использовать статус ischecked (true или false) для привязки к 4 различным элементам управления медиаплеером и переключения свойства отключения звука на этих элементах управления.
если у вас есть 4 элемента управления мультимедиа и вы хотите, чтобы все они отключались одной кнопкой, нет необходимости в мультипривязке, просто привяжите их все к кнопке напрямую без конвертера
Я попробовал это в коде, создав 4 отдельных экземпляра привязки к одной и той же кнопке переключения. но единственный, кто функционировал, был последним связанным. Привязка одной кнопки к одному элементу управления видео в коде работает иначе.
Но это должно работать, и это правильно в вашем случае. Почему вы вообще пытаетесь реализовать элементы XAML в коде? на самом деле гораздо проще использовать XAML, поскольку он был предназначен для...
Элементы управления видео создаются динамически в коде по мере необходимости, и их число может варьироваться от 1 до 4 в зависимости от различных параметров. В большинстве случаев это будет 4, но может варьироваться. Следовательно, я не могу выполнить привязку в xaml, когда даже не знаю, сколько элементов управления будет существовать во время выполнения.
Имеет смысл! Тем не менее, вы можете привязать все эти элементы управления к одному и тому же переключателю. Здесь не нужен мультибиндинг и не нужен Конвертер. Если все это сводит вас с ума, вы все равно можете использовать команду i, чтобы отключить или включить звук при нажатии кнопки-переключателя. Это также даст вам преимущество в том, что вы сможете восстановить предыдущее состояние, в котором они находились. Пример: все отключены, кроме одного-> щелчок-> все отключены-> щелчок -> все отключены -> 4 медиаплеера, воспроизводящие звук вместо одного это было раньше
Я попробую исходный вариант привязки, который вы предложили, снова, если это не удастся, я посмотрю на вариант icomand и сообщу. Я очень разочарован тем, что не могу понять, почему это мультибиндинг не работает. это казалось элегантным решением.
Вы используете шаблон MVVM или все делаете на основе событий?
Все дело в коде в классе главного окна в методах, вызываемых, когда известно количество требуемых игроков. IMultiValueConverter — это отдельный класс в том же проекте.
хорошо, в этом случае я рекомендую изучить MVVM, но это выходит за рамки этого вопроса ... вместо использования icomand вы можете использовать событие щелчка, чтобы отключить звук игроков Click->If((sender as ToggleButton).IsChecked){Store current Condition and mute all}else{->restore previous condition}
Я попробую все эти варианты. Благодарю.
Вы пытались указать режим привязки в своих индивидуальных привязках?





ну, я снова попробовал несколько вариантов, и ни один из них не работает, кроме кода в событии нажатия кнопки
Мультибиндинг вообще не работает. Я вижу в точках останова, что свойство Mute вызывается 4 раза для 4 элементов управления, но параметр значения никогда не обновляется до нового значения свойства.
Я также попытался привязать одну кнопку к 4 различным элементам управления.
foreach(Player player in lsPlayers)
{
btnMuteToggle.SetBinding(SimpleButton.IsCheckedProperty, new Binding("Mute")
{
Source = player,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
Mode = BindingMode.OneWayToSource
});
}
Это просто приводит к вызову свойства отключения звука одного объекта игрока. Вы не можете привязать более одного элемента управления к одной и той же кнопке. Это просто не работает.
поэтому я просто назвал 4 объекта в событии щелчка.
Я считаю, что в этом случае вы можете захотеть привязать эти 4 свойства к свойству отключения звука по отдельности и убедиться, что для каждого режима установлено значение TwoWay. Но если MultiValueConverter поддерживает это, я не могу особо спорить с вашим подходом.
Похоже, вы не создали свойство зависимости для Mute. это жизненно важно для рабочего процесса привязки WPF и, как правило, легче масштабируется, чем NotifyPropertyChanged, поскольку NotifyPropertyChanged может требовать от вас большего управления. DependencyProperty будет абстрагироваться как от отправки, так и от получения обновлений вашего свойства, а поддержка редактора Xaml для него лучше.
Я считаю, что привязка WPF хороша в теории, но все же требует гораздо больше работы, чем нужно. Иметь функцию. Я добавляю его во все свои модели представления и элементы управления WPF.
/// <summary>
/// simplify wpf binding
/// </summary>
/// <param name = "name"></param>
/// <param name = "type"></param>
/// <param name = "preferNull">Fair Warning. if you create an instance, you will have also created a singleton of this property for all instances of this class. </param>
/// <returns></returns>
private static DependencyProperty AddDp(string name, Type type, bool preferNull = true)
{
return DependencyProperty.Register(name, type, typeof(Setting),
new PropertyMetadata((!preferNull || type.IsValueType) ? Activator.CreateInstance(type) : null));
}
Просто наследуйтесь от DependencyObject, и вы можете заставить mute выглядеть примерно так:
public static readonly DependencyProperty MuteDp = AddDp(nameof(Mute), typeof(bool));
public bool Mute
{
get => (bool)GetValue(MuteDp);
set { if (value != Mute) SetValue(MuteDp, value); }
}
Но будьте осторожны! Иногда привязка WPF к свойству зависимости обновляет внутренние значения свойства зависимости без ввода установщика соответствующего свойства! Это было в случае с MultiValueBinding, который я использовал. это означает, что он никогда не может касаться аксессора Mute::Set. Это может быть довольно проблематично, чтобы противостоять этой проблеме, вы можете использовать различные обратные вызовы, доступные для DependencyObject!
private static DependencyProperty AddDp(string name, Type type, bool preferNull = true)
{
var dp = DependencyProperty.Register(name, type, typeof(Setting),
new PropertyMetadata(
(!preferNull || type.IsValueType) ? Activator.CreateInstance(type) : null
,new PropertyChangedCallback((dobj, dpe)=>
{
//after property changed.
//forcing usage of set accessor
((MuteContainerObj)dobj).Value = ((strong text)dobj).Value;
//or forcibly use an update function
((MuteContainerObj)dobj).MuteUpdated();
}),new CoerceValueCallback((dobj, o)=> {
//before property changed
return o;
})), new ValidateValueCallback((o)=> {
//before property change events
return true;
}));
return dp;
}
Я прочитал это 3 раза, и я не понимаю, что вы пытаетесь сделать в целом.