Xaml 绑定不会更新(一切似乎都应该工作)



我一直在一个独特的项目上工作了一段时间,最近我写了一个自定义的"绑定系统"(用于外部代码),它工作得很好,但是今天我需要一些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绑定到非静态类

使用另一个答案中的代码