【问题标题】:WPF User Control Dependency Property not working when bound to a ViewModel property绑定到 ViewModel 属性时,WPF 用户控件依赖属性不起作用
【发布时间】:2014-08-18 20:57:34
【问题描述】:

我有两个用户控件:一个 LocationTreeView 和一个 LocationPicker。 LocationTreeView 将 Locations 组织成一个树形结构。由于涉及的位置数量众多,一次只加载树的一部分(随着项目的展开,一次加载一级)。

LocationPicker 只不过是一个带有按钮的文本块,它可以打开一个带有 LocationTreeView 的模式窗口。

当我将 LocationPicker 的“SelectedLocation”属性绑定到我的 Viewmodel 时,它可以正常工作。当我将 LocationTreeView 绑定到视图模型时,绑定似乎根本没有任何效果。当我将 LocationTreeView 绑定到“虚拟”LocationPicker(绑定到我的视图模型)时,它可以工作。 如何让我的 LocationTreeView 绑定到我的视图模型?

public partial class LocationTreeView: UserControl
{
    public EventHandler LocationChanged;
    ...

    public static readonly DependencyProperty SelectedLocationProperty = 
         DependencyProperty.Register("SelectedLocation",typeof(Location), typeof(LocationTreeView),
         new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, SelectedLocationChanged));
    ...

    public static void SelectedLocationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
         LocationTreeView sender = (d as LocationTreeView);
         Location loc = e.NewValue as Location;
         //Navigate the treeview to the selected location
         sender.LoadLTreeViewPathToLocation(loc);
    }

    public Location SelectedLocation
    {
         get { return (Location)GetValue(SelectedLocationProperty); }
         set
         {
              if (SelectedLocation != value)
              {
                 SetValue(SelectedLocationProperty, value);
                 if (LocationChanged != null)
                 {
                     LocationChanged(this, EventArgs.Empty);
                 }
              }
         }
    }
    ...
}

绑定到另一个控件时,此控件上的绑定可以正常工作,但绑定到我的视图模型时则不行。我在 SelectedLocationChanged 回调中设置了一个断点,当我设置 viewmodel 属性(它确实实现了 INotifyPropertyChanged)时,它似乎没有被触发

public partial class LocationPicker: UserControl
{
    public static readonly DependencyProperty SelectedLocationProperty = 
         DependencyProperty.Register("SelectedLocation",typeof(Location), typeof(LocationPicker),
         new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
    ...

    public Location SelectedLocation
    {
         get { return (Location)GetValue(SelectedLocationProperty); }
         set { SetValue(SelectedLocationProperty, value); }
    }
    ...

    private void Button_Click(object sender, RoutedEventArgs e)
    {
         // create a window with a locationtreeview on it. Set the treeview's
         // selectedlocation property, open the window, wait for the window to close,
         //  set this.SelectedLoctation to the treeview's selected location.
    }
}

对于遗漏了这么多代码,我深表歉意。我的工作环境使我无法复制/粘贴。

我省略了 ViewModel 的代码。我非常有信心这不是问题。


更新: LocationTreeView 有一个在 xaml 中设置的 ViewModel

<UserControl.DataContext>
    <VM:LocationTreeViewViewModel />
</UserControl.DataContext>

LocationPicker 没有 ViewModel。 在我使用控件的窗口上,xaml 看起来像这样

<Widow.DataContext>
    <VM:TestWindowViewModel />
</Window.DataContext>
<Grid>
...
<UC:LocationPicker x:Name="picker" SelectedLocation="{Binding Location}" /> 

<!-- this does not work -->
<UC:LocationTreeView SelectedLocaiton="{Binding Location}" />

<!-- but this works --->
<UC:LocationTreeView SelectedLocaiton="{Binding SelectedLocation, ElementName=picker}" />
...
</Grid>

【问题讨论】:

  • 能否请您出示Binding的代码?
  • 直到明天我才能验证这一点,但我认为问题在于,当 LocationTreeView 绑定到视图模型时,它使用 LocationTreeView 的默认 DataContext 而不是窗口的 DataContext。这可以解释为什么它在绑定到另一个控件时会起作用,因为在绑定表达式中设置 ElementName(或 RelativeSource 等)会显式设置该表达式的 DataContext。

标签: c# wpf xaml mvvm user-controls


【解决方案1】:

如果您想将数据从您的视图模型绑定到LocationTreeView,那么您应该使用视图模型中的属性来进行数据绑定。如果您的视图模型中有一个名为 SelectedLocationInViewModel 的属性,那么您应该使用它来绑定数据:

<UC:LocationTreeView SelectedLocation="{Binding SelectedLocationInViewModel}" />

我想我知道你现在的问题是什么......你想在UserControl 中定义一些属性并将数据绑定到它们,但是数据绑定到视图模型中的属性设置为DataContext。您需要使用RelativeSource Binding 来执行此操作...只需查看这些示例中的Binding Paths:

将数据绑定到UserControl 中声明的属性UserControl

<ItemsControl ItemsSource="{Binding PropertyName, RelativeSource={RelativeSource 
    AncestorType={x:Type YourPrefix:YourUserControl}}}" />

将数据绑定到在任何对象集中声明为DataContext 的属性:

<ItemsControl ItemsSource="{Binding PropertyName}" />

【讨论】:

    猜你喜欢
    • 2019-12-14
    • 1970-01-01
    • 2015-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多