Я только начинаю с 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 изменяет значение, но он не обновляется в ярлыке, поэтому я предполагаю, что привязка неверна. Может кто-нибудь сказать мне, что не так? благодаря
Ваш код будет работать, если вы измените свой класс на этот...
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%, и в целом это хорошая вещь, чтобы рассмотреть.
Вы хотите использовать свойство для этого, а также реализовать 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
Если вы хотите, чтобы изменения в вашей собственности были подхвачены пользовательским интерфейсом, вы должны реализовать интерфейс INotifyPropertyChanged
и поднять событие каждый раз, когда изменяется значение свойства. Поэтому idCounter
должен выглядеть следующим образом:
private int _idCounter;
public int idCounter
{
get { return _idCounter; }
set
{
if (_idCounter != value)
{
_idCounter = value;
OnPropertyChanged("idCounter");
}
}
}
Когда вы создаете привязку к свойству, вы используете Path
Связывание работает в контексте привязки, поэтому вам нужно указать, откуда взять этот Path
. Самый простой способ сделать это - установить DataContext
. Поэтому в вашем случае инициализация должна выглядеть примерно так:
Binding b = new Binding("idCounter");
b.Mode = BindingMode.OneWay;
b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
myLabel.SetBinding(Label.ContentProperty, b);
DataContext = this;
Как предложил @d.moncada в своем ответе, вы должны создать специальную модель просмотра
inherit
от INotifyPropertyChange, ониimplement
его. Хороший ответ, хотя.