0

我有一个名为 ActionsTreeView 的 UserControl,我使用 MVVM 实践构建了其中我有一个 IPluginsProvider 接口,用于填充我的 UserControl 中的数据。我希望能够提供一个实现此IContentProvider接口的对象作为参数来初始化我的 UserControl 的 ViewModel。

到目前为止,这是我的方法,这是行不通的。我想知道我是否走在正确的道路上?我在我的用户控件中声明了一个DependencyProperty对我想要实例化此 UserControl 的 mainWindow 可见的用户控件。此代码只是尝试将 PluginsProvider 对象传递给需要它来构建其 ViewModel 的我的 UserControl。

我的 UserControl 中的 PluginProviderDependencyProperty设置器永远不会被击中,因为我的PropertyChanged处理程序在 MainWindow.xaml.cs 中始终为空联系?

ActionsTreeView.xaml.cs

public partial class ActionsTreeView: UserControl
{
    public static readonly DependencyProperty PluginProviderProperty = DependencyProperty.Register("PluginProvider", typeof(Models.IPluginsProvider), typeof(ActionsTreeView), new FrameworkPropertyMetadata(null, OnPluginProviderChanged));

    private ViewModels.ActionsTreeViewModel vm;

    public ActionsTreeView()
    {
        //Wire-up our ViewModel with the data provider and bind it to DataContext for our user control
        //This is a Mock-up until I figure out a way to get the real provider here

        Models.IPluginProvider pluginSource = new Models.MockPluginProvider();

        vm = new ViewModels.ActionsTreeViewModel(pluginSource );
        this.DataContext = vm;

        InitializeComponent();
    }

    private static void OnPluginProviderChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
    {
        ((ActionsTreeView)source).PluginProvider = (Models.IPluginsProvider)e.NewValue;
    }

    public Models.IPluginsProvider PluginProvider 
    {
        get
        { 
            return (Models.IPluginsProvider)GetValue(PluginProviderProperty);
        }

        set 
        { 
            SetValue(PluginProviderProperty, value); 
            vm.SetPluginSource(PluginProvider);
        } 
    }...

主窗口.xaml.cs

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public MainWindow()
    {
        InitializeComponent();

        this.ActionProvider = new Models.PluginsProvider(Library.Action.AvailableActions);
    }

    private Models.IPluginsProvider _actionProvider;
    public Models.IPluginsProvider ActionProvider
    {
        get { return _actionProvider; }
        set 
        { 
            _actionProvider = value;
            OnPropertyChanged("ActionProvider");
        }
    }
    protected void OnPropertyChanged(string property)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)  //HANDLER IS ALWAYS NULL
        {
            handler(this, new PropertyChangedEventArgs(property));
        }
    }
}

在 MainWindow.xaml 中使用我的 UserControl

<Grid>

    <UserControls:ActionsTreeView PluginProvider="{Binding ActionProvider}" />

</Grid>
4

2 回答 2

1

我认为您不能在 xaml 的 ctor 中传递参数。

如果您在后面的代码中创建控件,则可以在 ctor(Param param) 中传递参数

不确定这是否适合 MVVM 模型,但我在常规代码中经常使用它

在 XAML 中使用框架作为放置 UserControl 的位置

于 2012-10-05T16:39:54.367 回答
0

好像您缺少绑定源

<Grid>
    <UserControls:ActionsTreeView PluginProvider="{Binding ActionProvider, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" />
</Grid>

由于您的属性ActionProvider是在其中声明的,MainWindow因此在绑定期间您需要引用相同的源,除非您已将其设置为窗口的数据上下文

如果在 MainWindow 中没有使用其他数据上下文,您也可以执行以下操作,那么您可以使用您拥有的原始绑定PluginProvider="{Binding ActionProvider}"

public MainWindow()
{
    InitializeComponent();

    this.ActionProvider = new Models.PluginsProvider(Library.Action.AvailableActions);
    DataContext = this;
}

我已经设置了DataContextto thiswhich 将有效地解决ActionProvider来自实例的绑定值this

额外的

您也可以选择删除INotifyPropertyChangedMainWindow因为它已经DependencyObject并且能够进行财产通知并声明DependencyPropertyActionProvider

例如

    public Models.IPluginsProvider ActionProvider
    {
        get { return (Models.IPluginsProvider)GetValue(ActionProviderProperty); }
        set { SetValue(ActionProviderProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ActionProvider.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ActionProviderProperty =
        DependencyProperty.Register("ActionProvider", typeof(Models.IPluginsProvider), typeof(MainWindow), new PropertyMetadata(null));

因此您无需担心手动更改通知,如果上述解决方案不适合您,您可能需要使用它,否则最好拥有。

于 2014-07-02T09:19:39.787 回答