Привязка кнопки WPF к свойству Convertback IMultiValueConverter не обновляет значение

У меня есть привязка от переключателя, подключенного в коде позади. Я хочу привязать состояние 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 игрока с отдельными элементами управления и привязать их к одному нажатию кнопки.

Я прочитал это 3 раза, и я не понимаю, что вы пытаетесь сделать в целом.

Denis Schaf 14.03.2019 15:17

Я пытаюсь заставить мультипривязки работать, чтобы щелкнуть одну кнопку переключения и использовать статус ischecked (true или false) для привязки к 4 различным элементам управления медиаплеером и переключения свойства отключения звука на этих элементах управления.

Manity 14.03.2019 15:26

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

Denis Schaf 14.03.2019 15:28

Я попробовал это в коде, создав 4 отдельных экземпляра привязки к одной и той же кнопке переключения. но единственный, кто функционировал, был последним связанным. Привязка одной кнопки к одному элементу управления видео в коде работает иначе.

Manity 14.03.2019 15:32

Но это должно работать, и это правильно в вашем случае. Почему вы вообще пытаетесь реализовать элементы XAML в коде? на самом деле гораздо проще использовать XAML, поскольку он был предназначен для...

Denis Schaf 14.03.2019 15:33

Элементы управления видео создаются динамически в коде по мере необходимости, и их число может варьироваться от 1 до 4 в зависимости от различных параметров. В большинстве случаев это будет 4, но может варьироваться. Следовательно, я не могу выполнить привязку в xaml, когда даже не знаю, сколько элементов управления будет существовать во время выполнения.

Manity 14.03.2019 15:37

Имеет смысл! Тем не менее, вы можете привязать все эти элементы управления к одному и тому же переключателю. Здесь не нужен мультибиндинг и не нужен Конвертер. Если все это сводит вас с ума, вы все равно можете использовать команду i, чтобы отключить или включить звук при нажатии кнопки-переключателя. Это также даст вам преимущество в том, что вы сможете восстановить предыдущее состояние, в котором они находились. Пример: все отключены, кроме одного-> щелчок-> все отключены-> щелчок -> все отключены -> 4 медиаплеера, воспроизводящие звук вместо одного это было раньше

Denis Schaf 14.03.2019 15:46

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

Manity 14.03.2019 15:52

Вы используете шаблон MVVM или все делаете на основе событий?

Denis Schaf 14.03.2019 15:54

Все дело в коде в классе главного окна в методах, вызываемых, когда известно количество требуемых игроков. IMultiValueConverter — это отдельный класс в том же проекте.

Manity 14.03.2019 16:06

хорошо, в этом случае я рекомендую изучить MVVM, но это выходит за рамки этого вопроса ... вместо использования icomand вы можете использовать событие щелчка, чтобы отключить звук игроков Click->If((sender as ToggleButton).IsChecked){Store current Condition and mute all}else{->restore previous condition}

Denis Schaf 14.03.2019 16:10

Я попробую все эти варианты. Благодарю.

Manity 14.03.2019 16:14

Вы пытались указать режим привязки в своих индивидуальных привязках?

Jody Sowald 07.08.2020 17:02
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
13
229
2

Ответы 2

ну, я снова попробовал несколько вариантов, и ни один из них не работает, кроме кода в событии нажатия кнопки

Мультибиндинг вообще не работает. Я вижу в точках останова, что свойство 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 для него лучше.

https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/how-to-implement-a-dependency-property

Я считаю, что привязка 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;
        
}

Другие вопросы по теме