我一直在一个独特的项目上工作了一段时间,最近我写了一个自定义的"绑定系统"(用于外部代码),它工作得很好,但是今天我需要一些MVVM风格的绑定来工作(用于内部UI)。经过一整天的谷歌搜索和尝试不同的东西,我仍然没有一个答案或工作代码。我几乎到了要加上" normal "的地步了绑定到我现有的绑定系统,然后收工。
无论如何……我的问题…
我试图使单向绑定从ViewModel类到UI元素. 这里有一些"规则"。我必须遵守虽然(像所有(公共)属性必须在静态类中(.在设计时一切正常VS可以解析绑定(如果数据上下文是在xaml中设置的,而不是在cs中)。绑定甚至update一次在启动时变为默认值,但在属性源更改时不变为.
TLDR;阅读粗体文本:)
代码:
[公共静态类]这里的属性是由外部代码在运行时
设置的。public static class StaticClass
{
public static string ExampleProperty
{
get
{
return ViewModel.Instance.ExampleProperty;
}
set
{
if (ViewModel.Instance.ExampleProperty != value) ViewModel.Instance.ExampleProperty = value;
}
}
}
[ViewModel]一个单例类,它为上面类中的静态属性保存非静态支持字段,并实现INotifyPropertyChanged
internal class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private static ViewModel _instance = null;
internal static ViewModel Instance
{
get
{
if (_instance is null) _instance = new();
return _instance;
}
}
private static string _exampleProperty { get; set; } = "Pls work";
public string ExampleProperty
{
get
{
return _exampleProperty;
}
set
{
_exampleProperty = value;
OnPropertyChanged();
}
}
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (propertyName is not null) PropertyChanged?.Invoke(null, new(propertyName));
}
}
[Xaml示例绑定]
<Button Content="{Binding ExampleProperty, UpdateSourceTrigger=PropertyChanged}" Click="Button_Click"/>
[MainWindow.cs]显然这是一个测试项目所以这只是将ExampleProperty
更改为Button.Click
事件上的随机数
public partial class MainWindow : Window
{
Random random = new();
public MainWindow()
{
InitializeComponent();
this.DataContext = ViewModel.Instance;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Button btn = (Button)sender;
StaticClass.ExampleProperty = random.Next(0, 69).ToString();
}
}
我做错了什么?如有任何帮助,不胜感激。
表达式
DataContext = new ViewModel();
将ViewModel类的不同实例分配给DataContext,而不是从ViewModel.Instance
返回的实例,因此
StaticClass.ExampleProperty = random.Next(0, 69).ToString();
不影响DataContext。你应该分配
DataContext = ViewModel.Instance;
你的ViewModel类没有正确地实现单例模式——它必须避免创建多个实例,例如通过声明一个私有构造函数。
视图根本不需要使用视图模型的单例方面。为了访问当前视图模型实例,转换DataContext:
private void Button_Click(object sender, RoutedEventArgs e)
{
Button btn = (Button)sender;
ViewModel vm = (ViewModel)btn.DataContext;
vm.ExampleProperty = random.Next(0, 69).ToString();
}
感谢对这个问题的评论:
Also be aware that it is possible to bind directly to static properties of a static class, even with change notification, thus eliminating the need for a singleton. See e.g. here: stackoverflow.com/a/41823852/1136211
(和答案)我已经成功地使用了静态和非静态绑定(终于…)。
用于将UI绑定到静态类
静态类:
public static class StaticClass
{
public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged;
#region Properties
public static string _exampleProperty = "Default value";
public static string ExampleProperty
{
get
{
return _exampleProperty;
}
set
{
if (_exampleProperty != value)
{
_exampleProperty = value;
OnStaticPropertyChanged();
}
}
}
#endregion
private static void OnStaticPropertyChanged([CallerMemberName]string propertyName = null)
{
StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(propertyName));
}
}
如何绑定到UI:
<TextBlock Text="{Binding Path=(local:StaticClass.ExampleProperty)}"/>
如何设置属性:
StaticClass.ExampleProperty = "New value that automatically updates the UI :)";
用于将UI绑定到非静态类
使用另一个答案中的代码