Привязка данных WPF и IValueConverter

Чтобы удалить узел из базы данных Firebase Realtime, вам нужна ссылка на его точный, полный путь. У вас есть такие ссылки при загрузке данных. Например, в onDataChange вы можете удалить каждый узел с помощью:

public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
    for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
        //Booking b = dataSnapshot1.getValue(Booking.class);
        dataSnapshot1.getRef().removeValue();
    }
}

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

В своем слушателе вы получаете значение от каждого дочернего узла и добавляете его в список, который затем отображаете в адаптере. Но вы не получаете клавишу каждого дочернего узла. Это означает, что в вашем списке / адаптере есть только часть знаний, необходимых для удаления узлов. К тому моменту, когда ваша функция deleteItem будет вызвана с позицией удаляемого элемента, уже невозможно найти клавишу этого узла.

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

Итак, сначала вы добавляете List<String> для ключей к вашему адаптеру:

ArrayList<Booking> bookings;
ArrayList<String> keys;

И принимаете это в конструкторе адаптера:

public MyAdapterBookings(Context c , ArrayList<Booking> b, ArrayList<String> k)
{
    context = c;
    bookings = b;
    keys = k;
}

Затем вы добавляете каждый ключ в onDataChange:

public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
    Log.d(TAG, "populating recyclerview");

    list = new ArrayList<Booking>();
    List<String> keys = new ArrayList<String>();
    for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
        Booking b = dataSnapshot1.getValue(Booking.class);
        list.add(b);
        keys.add(dataSnapshot1.getKey());
    }
    adapter = new MyAdapterBookings(CustomerProfile.this, list, keys);
    recyclerView.setAdapter(adapter);
    adapter.notifyDataSetChanged();
}

И, наконец, вы можете найти ключ для удаляемого элемента:

public void deleteItem(int position){
    String key = keys.get(position);
    DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("Booking");
    ref.child(key).removeValue();
}
13
задан urini 6 October 2008 в 17:44
поделиться

4 ответа

(см. редактирования ниже;последние обновления: № 2)

Это не обновляет, потому что Ваш Person объект не способен к уведомлению ничего, что значение FirstName или LastName изменилось. Посмотрите этот Вопрос .

И вот то, как Вы реализуете INotifyPropertyChanged. ( Обновленный, посмотрите Редактирование 2 )

using System.ComponentModel;

class Person : INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;

    string _firstname;
    public string FirstName {
        get {
            return _firstname;
        }
        set {
            _firstname = value;
            onPropertyChanged( "FirstName", "FullName" );
        }
    }

    string _lastname;
    public string LastName {
        get {
            return _lastname;
        }
        set {
            _lastname = value;
            onPropertyChanged( "LastName", "FullName" );
        }
    }

    public string FullName {
        get {
            return _firstname + " " + _lastname;
        }
    }

    void onPropertyChanged( params string[] propertyNames ) {
        PropertyChangedEventHandler handler = PropertyChanged;

        if ( handler != null ) {
            foreach ( var pn in propertyNames ) {
                handler( this, new PropertyChangedEventArgs( pn ) );
            }
        }
    }
}

Редактирование 1

На самом деле, так как Вы после имени и обновления фамилии, и Path=FirstName и такой, работает просто великолепно, я не думаю, что Вам будет нужен преобразователь вообще. Приблизительно TextBlocks так же допустимы, и могут на самом деле работать лучше, когда Вы локализуете к справа налево язык.

Редактирование 2

я понял это. Это не уведомляется, что свойства обновили, потому что это связывает с самим объектом, не одним из тех свойств. Даже когда я сделал Person DependencyObject и сделал FirstName и LastName DependencyProperties, это не обновит.

Вы будете , должны использовать FullName свойство, и я имею, обновляют код Person класс выше для отражения этого. Тогда можно связать Title. ( Примечание: я установил эти Person объект как Window DataContext.)

Title="{Binding Path=FullName, Mode=OneWay}"

, Если Вы редактируете имена в TextBox и хотите имя, изменившее отраженный сразу вместо того, когда эти TextBox теряет фокус, можно сделать это:

<TextBox Name="FirstNameEdit"
    Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged}" />

я знаю, что Вы не хотели использовать FullName свойство, но что-либо, что выполнит то, что Вы хотите, вероятно, было бы что-то вроде устройства Rube Goldberg. Такой как реализация INotifyPropertyChanged и Person свойство на Window сам класс, наличие эти Window слушает на PropertyChanged событие для увольнения Window PropertyChanged событие и использование родственника, связывающего как следующее. Вы также установили бы Person свойство прежде InitializeComponent() или огонь PropertyChanged после установки Person свойство так, чтобы это обнаружилось, конечно. (Иначе это будет null во время [1 136] и должно знать, когда это будет Person.)

<Window.Resources>
    <loc:PersonNameConverter
        x:Key="conv" />
</Window.Resources>
<Window.Title>
    <Binding
        RelativeSource="{RelativeSource Self}"
        Converter="{StaticResource conv}"
        Path="Person"
        Mode="OneWay" />
</Window.Title>
11
ответ дан 1 December 2019 в 21:25
поделиться

Для привязки, которая будет обновлена, Ваш класс человека должен реализовать INotifyPropertyChanged, чтобы позволить привязке знать, что свойства объекта были udpated. Можно также сохранить себя от дополнительного преобразователя путем обеспечения fullName свойства.

using System.ComponentModel;

namespace INotifyPropertyChangeSample
{
    public class Person : INotifyPropertyChanged
    {
        private string firstName;
        public string FirstName
        {
            get { return firstName; }
            set
            {
                if (firstName != value)
                {
                    firstName = value;
                    OnPropertyChanged("FirstName");
                    OnPropertyChanged("FullName");
                }
            }
        }

        private string lastName;
        public string LastName
        {
            get { return lastName; }
            set
            {
                if (lastName != value)
                {
                    lastName = value;
                    OnPropertyChanged("LastName");
                    OnPropertyChanged("FullName");
                }
            }
        }

        public string FullName
        {
            get { return firstName + " " + lastName; }
        } 

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }

        #endregion
    }
}

Ваша Привязка будет теперь похожа на это:

<TextBlock Text="{Binding Person.FullName}" />
1
ответ дан 1 December 2019 в 21:25
поделиться

Можно также использовать MultiBinding.. Свяжите с объектом Человека, FirstName и LastName. Тем путем значение обновляется, как только FirstName или LastName бросают измененное событие свойства.

<MultiBinding Converter="{IMultiValueConverter goes here..}">
    <Binding />
    <Binding Path="FirstName" />
    <Binding Path="LastName" />
</MultiBinding>

Или если Вы только используете FirstName и LastName, разделите объект Человека от привязки до чего-то вроде этого:

<MultiBinding Converter="{IMultiValueConverter goes here..}">
    <Binding Path="FirstName" />
    <Binding Path="LastName" />
</MultiBinding>

И MultiValueConverter похож на это:

class PersonNameConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
            return values[0].ToString() + " " + values[1].ToString();
    }

    public object ConvertBack(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
            throw new NotImplementedException();
    }
}

, Но конечно, выбранные работы ответа также, но MultiBinding работает более изящно...

14
ответ дан 1 December 2019 в 21:25
поделиться

Я не имею, проверяют его, но можете Вы также пробовать следующий

<TextBlock Text="{Binding Path=/, Converter={StaticResource personNameConverter}}" />
0
ответ дан 1 December 2019 в 21:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: