Связывание метки с переменной

1

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

public partial class MainWindow : Window
{
    int idCounter;

    public MainWindow()
    {
        InitializeComponent();


        Binding b = new Binding();
        b.Source = idCounter;
        b.Mode = BindingMode.OneWay;
        b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;

        myLabel.SetBinding(Label.ContentProperty,b);
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        idCounter++;
    }
}

Кнопка работает, idCounter изменяет значение, но он не обновляется в ярлыке, поэтому я предполагаю, что привязка неверна. Может кто-нибудь сказать мне, что не так? благодаря

Теги:
wpf
binding
event-handling
controls

3 ответа

4
Лучший ответ

Ваш код будет работать, если вы измените свой класс на этот...

  public partial class Window1 : Window, INotifyPropertyChanged
    {
        private int _idCounter;
        public int IdCounter
        {
            get { return _idCounter; }
            set
            {
                if (value != _idCounter)
                {
                    _idCounter = value;
                    OnPropertyChanged("IdCounter");
                }
            }
        }
        public Window1()
        {
            InitializeComponent();
            myLabel.SetBinding(ContentProperty, new Binding("IdCounter"));
            DataContext = this;
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            IdCounter++;
        }
        #region INotifyPropertyChanged Implementation
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string name)
        {
            var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
        #endregion
    }

Некоторые из проблем, которые у вас были, - это...

Само окно должно реализовать INotifyPropertyChanged, чтобы механизм привязки мог наложить на него ухо.

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

Вы должны установить DataContext для любого класса, объявленного IdCounter (в этом случае MainWindow). Отчасти проблема заключалась в том, что у механизма привязки не было DataContext.

Параметр BindingMode был красно-селедным, так как по умолчанию привязка Label привязывается по умолчанию.

UpdateSourceTrigger был red-herring, поскольку в содержании метки нет механизма для обновления исходного свойства. Содержимое метки не похоже на текстовое поле, в котором пользователь может ввести код, о котором должен знать код. Когда вы привязываетесь к чему-то, что пользователь не может изменить, забудьте о UpdateSourceTrigger, это свойство Target, которое учитывается.

Обработчик должен отметить событие. Это хорошая практика и не влияет на привязку.

Конструктору привязки нужен только путь.

Этот код даст вам ожидаемый результат; т.е. что метка обновляется при нажатии кнопки. Проверено, скомпилировано и выполнено на vs2013,.net 4.5.

Другие респонденты сказали, что вы должны использовать View Model. Я согласен с этим 100%, и в целом это хорошая вещь, чтобы рассмотреть.

  • 2
    Технически ваши объекты не inherit от INotifyPropertyChange, они implement его. Хороший ответ, хотя.
  • 1
    @JohnathonSullinger, спасибо за проницательную голову. Я отредактирую Т.А.
2

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

Вот пример использования простой ViewModel

XAML:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:converters="clr-namespace:WpfApplication1"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <Label Width="200" Height="50" Content="{Binding MyLabel}"/>
        <Button Height="30" Width="100" Content="Increment" Click="Button_Click" />
    </StackPanel>
</Window>

xaml.cs:

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        MainViewModel vm = new MainViewModel();
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = vm;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            vm.MyLabel += 1;
        }
    }
}

MainViewModel.cs:

namespace WpfApplication1
{
    public class MainViewModel : INotifyPropertyChanged
    {
        #region Members
        private int _myLabel;
        #endregion Members

        #region Properties
        public int MyLabel
        {
            get
            {
                return _myLabel;
            }
            set
            {
                _myLabel = value;
                NotifyPropertyChanged("MyLabel");
            }
        }

        #endregion Properties

        public MainViewModel()
        {
        }

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }
}

Примечание. В идеале вы бы хотели использовать Command для Button вместо обработчика события Click

1
  1. Вы не можете привязываться к чему-то частному или к полю, чтобы преобразовать его в общедоступное. Вы можете узнать больше о том, что является истинным источником привязки здесь
  2. Если вы хотите, чтобы изменения в вашей собственности были подхвачены пользовательским интерфейсом, вы должны реализовать интерфейс INotifyPropertyChanged и поднять событие каждый раз, когда изменяется значение свойства. Поэтому idCounter должен выглядеть следующим образом:

    private int _idCounter;
    
    public int idCounter
    {
        get { return _idCounter; }
        set
        {
            if (_idCounter != value)
            {
                _idCounter = value;
                OnPropertyChanged("idCounter");
            }
        }
    }
    
  3. Когда вы создаете привязку к свойству, вы используете Path

  4. Связывание работает в контексте привязки, поэтому вам нужно указать, откуда взять этот Path. Самый простой способ сделать это - установить DataContext. Поэтому в вашем случае инициализация должна выглядеть примерно так:

    Binding b = new Binding("idCounter");
    b.Mode = BindingMode.OneWay;
    b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
    
    myLabel.SetBinding(Label.ContentProperty, b);
    DataContext = this;
    
  5. Как предложил @d.moncada в своем ответе, вы должны создать специальную модель просмотра

Ещё вопросы

Сообщество Overcoder
Наверх
Меню