我有很多现有的业务对象,其中包含许多属性和集合,我想在其中绑定用户接口。在这些对象中使用DependencyProperty
或ObservableCollections
不是一种选择。据我所知,当我修改这些对象时,我希望有一种机制来在我执行此操作时更新所有UI控件。另外,我也不知道哪些UI控件绑定到这些对象以及哪些属性。
这是我现在尝试做的简化代码:
public class Artikel
{
public int MyProperty {get;set;}
}
public partial class MainWindow : Window
{
public Artikel artikel
{
get { return (Artikel)GetValue(artikelProperty); }
set { SetValue(artikelProperty, value); }
}
public static readonly DependencyProperty artikelProperty =
DependencyProperty.Register("artikel", typeof(Artikel), typeof(MainWindow), new UIPropertyMetadata(new Artikel()));
public MainWindow()
{
InitializeComponent();
test.DataContext = this;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
artikel.MyProperty += 1;
// What can I do at this point to update all bindings?
// What I know at this point is that control test or some of it's
// child controls bind to some property of artikel.
}
}
<Grid Name="test">
<TextBlock Text="{Binding Path=artikel.MyProperty}" />
</Grid>
这是,我试图将我的对象打包到DependencyProperty并尝试在此调用UpdateTarget,但没有成功。
如何更新相应的UI控件?
我希望我描述的情况足够好。
答案 0 :(得分:8)
使用INotifyPropertyChanged
是DependencyProperties的一个很好的替代方案。
如果您实现了界面,则可以使用null
作为参数引发PropertyChanged
事件,以通知UI所有属性都已更改。
答案 1 :(得分:1)
(我假设您不能将INotifyPropertyChanged添加到业务对象中,并且您不希望在MVVM中添加另一个“数据模型视图”包装对象层。)
您可以通过调用BindingExpression.UpdateTarget()手动更新其数据源中的绑定属性。
myTextBlock.GetBindingExpression(TextBlock.TextProperty).UpdateTarget();
要更新控件或窗口上的所有绑定,您可以使用以下内容:
using System.Windows.Media;
...
static void UpdateBindings(this DependencyObject obj)
{
for (var i=0; i<VisualTreeHelper.GetChildrenCount(obj); ++i)
{
var child = VisualTreeHelper.GetChild(obj, i);
if (child is TextBox)
{
var expression = (child as TextBox).GetBindingExpression(TextBox.TextProperty);
if (expression != null)
{
expression.UpdateTarget();
}
}
else if (...) { ... }
UpdateBindings(child);
}
}
如果你绑定了一组不同的属性,而不是像上面那样单独处理它们,你可以将上面的内容与this approach结合起来枚举一个控件上的所有依赖属性,然后从每个属性中获取任何BindingExpression;但这依赖于不会特别有效的反思。
作为脚注,如果要显式写回数据源,还可以使用BindingExpression.UpdateSource()。控件通常会在值变化或失去焦点时执行此操作,但您可以控制此操作并使用{Binding Foo, UpdateSourceTrigger=Explicit}
手动执行。
答案 2 :(得分:1)
正如我所知,当我修改这些对象时,我希望有一种机制来在我执行此操作时更新所有UI控件。
您会发现处理此问题的最简单和可维护的方法是为要在UI中呈现的每个类实现视图模型类。如果您可以修改基础类,则可能是这样,如果不能,则几乎可以肯定。
您无需为此使用依赖项属性。只有绑定的目标需要依赖属性,也就是说UI中的控件。您的视图模型对象是源;他们只需要实施INotifyPropertyChanged
。
是的,这意味着您需要构建包含UI中公开的每个属性的属性的类,并且这些类需要包含可观察的子视图模型集合,并且您必须实例化和填充这些类及其在运行时的集合。
这通常不像听起来那么大,而且在你的情况下它可能更少。构建绑定到数据模型的视图模型的传统方法是构建如下属性:
public string Foo
{
get { return _Model.Foo; }
set
{
if (value != _Model.Foo)
{
_Model.Foo = value;
OnPropertyChanged("Foo");
}
}
}
但是,正如您所声称的,您知道何时更新对象,并且您只想将更新推送到UI,您可以实现只读属性,以及何时更新基础数据模型使视图模型引发PropertyChanged
,并将事件args的PropertyName
属性设置为null,这将告诉绑定“此对象上的每个属性都已更改;更新所有绑定目标。”