wpf 将标签绑定到变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23716059/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Binding label to a variable
提问by Safiron
I am just starting with WPF and I am trying to setup binding between a local variable and a label. Basicaly I want to update the label when local variable changes. I was searching for solution but they all just use textbox as a source not just class variable and I am not even sure it works this way. So here is my code.
我刚开始使用 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++;
}
}
Button does work, idCounter changes value, but it does not update in label so I guess binding is wrong. Can someone tell me what is wrong? Thanks
按钮确实有效,idCounter 更改了值,但它不会在标签中更新,所以我猜绑定是错误的。有人可以告诉我出了什么问题吗?谢谢
回答by Gayot Fow
Your code will work if you change your class to this...
如果您将课程更改为此,您的代码将起作用......
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
}
Some of the issues you were having are...
您遇到的一些问题是...
The window itself should implement INotifyPropertyChanged so that the binding engine can place an ear on it.
窗口本身应该实现 INotifyPropertyChanged 以便绑定引擎可以将耳朵放在它上面。
the IdCounter needs to be public and have a public getter on it so that the binding engine can 'get' it.
IdCounter 需要是公开的,并且有一个公开的 getter,以便绑定引擎可以“获取”它。
You should set the DataContext to whatever class has declared IdCounter (the MainWindow in this case). Part of the problem was that the binding engine had no DataContext.
您应该将 DataContext 设置为已声明 IdCounter 的任何类(在本例中为 MainWindow)。部分问题是绑定引擎没有 DataContext。
The BindingMode setting was a red-herring since a Label binds that way by default.
BindingMode 设置是一个红鲱鱼,因为默认情况下 Label 以这种方式绑定。
The UpdateSourceTrigger was a red-herring since the content of the label does not have a mechanism to update the source property. A label's content is not like a text box where the user can type something that the code needs to know about. When you're binding to something that the user cannot change, forget about UpdateSourceTrigger, it's the Targetproperty that counts.
UpdateSourceTrigger 是一个红鲱鱼,因为标签的内容没有更新源属性的机制。标签的内容不像文本框,用户可以在其中输入代码需要了解的内容。当您绑定到用户无法更改的内容时,忘记 UpdateSourceTrigger,它是重要的Target属性。
The handler should mark the event. This is good practice and did not affect the binding.
处理程序应标记该事件。这是一种很好的做法,不会影响绑定。
The binding constructor needs only the path.
绑定构造函数只需要路径。
This code will give you your expected result; i.e., that the label updates when the button is clicked. Checked, compiled, and executed on vs2013, .net 4.5.
此代码将为您提供预期的结果;即,当单击按钮时标签更新。在 vs2013、.net 4.5 上检查、编译和执行。
The other respondents said you should use a View Model. I agree with this 100%, and overall it's a good thing to consider.
其他受访者表示您应该使用视图模型。我 100% 同意这一点,总的来说这是一件值得考虑的事情。
回答by d.moncada
You want to use a property to do this, as well as implementing INotifyPropertyChangedso that the label's content gets updated when the property changes.
您希望使用属性来执行此操作,并实施INotifyPropertyChanged以便label在属性更改时更新 的内容。
Here's an example using a simple ViewModel
这是一个使用简单的示例 ViewModel
xaml:
xml:
<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:
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:
主视图模型.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
}
}
Note: Ideally, you would want to use a Commandfor the Buttoninstead of a Click event handler
注意:理想情况下,您希望使用CommandforButton而不是 Click 事件处理程序
回答by dkozl
- You cannot bind to something that is private or a field so convert it into public property. You can find more as to what is a valid binding source here
If you want changes to your property be picked up by UI you should implement
INotifyPropertyChangedinterface and raise event each time value of the property changes. SoidCountershould look more like this:private int _idCounter; public int idCounter { get { return _idCounter; } set { if (_idCounter != value) { _idCounter = value; OnPropertyChanged("idCounter"); } } }When you create binding to property you use
PathBinding works in binding context so you need to specify from where to take this
Path. Easiest way to do that is to setDataContext. So in your case initialization should look more like this:Binding b = new Binding("idCounter"); b.Mode = BindingMode.OneWay; b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; myLabel.SetBinding(Label.ContentProperty, b); DataContext = this;As @d.moncada suggested in his answer you should create dedicated view model
- 您不能绑定到私有或字段的内容,因此将其转换为公共属性。您可以在此处找到有关什么是有效绑定源的更多信息
如果您希望 UI 获取对您的属性的更改,您应该实现
INotifyPropertyChanged接口并在每次属性值更改时引发事件。所以idCounter应该看起来更像这样:private int _idCounter; public int idCounter { get { return _idCounter; } set { if (_idCounter != value) { _idCounter = value; OnPropertyChanged("idCounter"); } } }当您创建绑定到您使用的属性时
Path绑定在绑定上下文中工作,因此您需要指定从何处获取 this
Path。最简单的方法是设置DataContext. 因此,在您的情况下,初始化应该更像这样:Binding b = new Binding("idCounter"); b.Mode = BindingMode.OneWay; b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; myLabel.SetBinding(Label.ContentProperty, b); DataContext = this;正如@d.moncada 在他的回答中建议的那样,您应该创建专用的视图模型

