WPF用户控制+;MVVM

WPF用户控制+;MVVM,wpf,mvvm,user-controls,dependency-properties,Wpf,Mvvm,User Controls,Dependency Properties,在网站上搜索了很多,阅读了很多类似的问题,但似乎没有什么能解决我对用户控制不理解的问题 我用MVVM实现了一个用户控件。基本上是一个文件夹网格,其中每个文件夹都是一个复选框和一个路径。用户可以选中复选框选择任何文件夹。 用户控件xaml是: <UserControl x:Class="TestDP.Views.ViewCTRL" [...]> <DataGrid Name="GridMain" ItemsSource="{Binding Folders}">

在网站上搜索了很多,阅读了很多类似的问题,但似乎没有什么能解决我对用户控制不理解的问题

我用MVVM实现了一个用户控件。基本上是一个文件夹网格,其中每个文件夹都是一个复选框和一个路径。用户可以选中复选框选择任何文件夹。 用户控件xaml是:

<UserControl x:Class="TestDP.Views.ViewCTRL" [...]>
        <DataGrid Name="GridMain" ItemsSource="{Binding Folders}">
        <DataGrid.Columns>
            <DataGridCheckBoxColumn Header="Cked" Binding="{Binding Cked,  UpdateSourceTrigger=PropertyChanged}" />
            <DataGridTextColumn Header="Path" Binding="{Binding Path}"/>
        </DataGrid.Columns>
    </DataGrid>
</UserControl>
public partial class ViewCTRL : UserControld
{
    public static DependencyProperty SelectedFoldersProperty =
        DependencyProperty.Register("SelectedFolders", typeof(ObservableCollection<Folder>), typeof(ViewCTRL),
        new FrameworkPropertyMetadata() { BindsTwoWayByDefault = true });

    public ObservableCollection<Folder> SelectedFolders
    {
        get{return (ObservableCollection<Folder>)GetValue(SelectedFoldersProperty);}
        set{SetValue(SelectedFoldersProperty, value);}}

    public ViewCTRL()
    {
        var vm = new ViewCTRLModel();
        InitializeComponent();
        GridMain.DataContext = vm;

        // bindings
        SetBinding(SelectedFoldersProperty, new Binding()
        {
            Source = GridMain.DataContext,
            Path = new PropertyPath("SelectedFoldersV"),
            UpdateSourceTrigger =   System.Windows.Data.UpdateSourceTrigger.PropertyChanged,
            Mode = BindingMode.TwoWay
        });
    }
    public class ViewCTRLModel : INotifyPropertyChanged
{
    [...]

    public void Folder_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        SelectedFoldersV = new ObservableCollection<Folder>(Folders.Where(x => x.Cked));
    }

    private ObservableCollection<Folder> folders;
    public ObservableCollection<Folder> Folders
    {
        get{return folders;}
        set{folders = value;OnPropertyChanged("Folders");}
    }

    private ObservableCollection<Folder> selectedFoldersV;
    public ObservableCollection<Folder> SelectedFoldersV
    {
        get{return selectedFoldersV;}
        set{selectedFoldersV = value;OnPropertyChanged("SelectedFoldersV");}
    }
    [...]
}
class ViewWPFModel : INotifyPropertyChanged
{
    public ViewWPFModel()
    {
        SelectedFoldersVMWPF = new ObservableCollection<Folder>();
        SelectedFoldersVMWPF.Add(new Folder() { Path = "uuu" });
    }

    private ObservableCollection<Folder> selectedFoldersVMWPF;
    public ObservableCollection<Folder> SelectedFoldersVMWPF
    {
        get {return selectedFoldersVMWPF;}
        set {selectedFoldersVMWPF = value; OnPropertyChanged("SelectedFoldersVMWPF");}
    }
}

后面的用户控制代码是:

<UserControl x:Class="TestDP.Views.ViewCTRL" [...]>
        <DataGrid Name="GridMain" ItemsSource="{Binding Folders}">
        <DataGrid.Columns>
            <DataGridCheckBoxColumn Header="Cked" Binding="{Binding Cked,  UpdateSourceTrigger=PropertyChanged}" />
            <DataGridTextColumn Header="Path" Binding="{Binding Path}"/>
        </DataGrid.Columns>
    </DataGrid>
</UserControl>
public partial class ViewCTRL : UserControld
{
    public static DependencyProperty SelectedFoldersProperty =
        DependencyProperty.Register("SelectedFolders", typeof(ObservableCollection<Folder>), typeof(ViewCTRL),
        new FrameworkPropertyMetadata() { BindsTwoWayByDefault = true });

    public ObservableCollection<Folder> SelectedFolders
    {
        get{return (ObservableCollection<Folder>)GetValue(SelectedFoldersProperty);}
        set{SetValue(SelectedFoldersProperty, value);}}

    public ViewCTRL()
    {
        var vm = new ViewCTRLModel();
        InitializeComponent();
        GridMain.DataContext = vm;

        // bindings
        SetBinding(SelectedFoldersProperty, new Binding()
        {
            Source = GridMain.DataContext,
            Path = new PropertyPath("SelectedFoldersV"),
            UpdateSourceTrigger =   System.Windows.Data.UpdateSourceTrigger.PropertyChanged,
            Mode = BindingMode.TwoWay
        });
    }
    public class ViewCTRLModel : INotifyPropertyChanged
{
    [...]

    public void Folder_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        SelectedFoldersV = new ObservableCollection<Folder>(Folders.Where(x => x.Cked));
    }

    private ObservableCollection<Folder> folders;
    public ObservableCollection<Folder> Folders
    {
        get{return folders;}
        set{folders = value;OnPropertyChanged("Folders");}
    }

    private ObservableCollection<Folder> selectedFoldersV;
    public ObservableCollection<Folder> SelectedFoldersV
    {
        get{return selectedFoldersV;}
        set{selectedFoldersV = value;OnPropertyChanged("SelectedFoldersV");}
    }
    [...]
}
class ViewWPFModel : INotifyPropertyChanged
{
    public ViewWPFModel()
    {
        SelectedFoldersVMWPF = new ObservableCollection<Folder>();
        SelectedFoldersVMWPF.Add(new Folder() { Path = "uuu" });
    }

    private ObservableCollection<Folder> selectedFoldersVMWPF;
    public ObservableCollection<Folder> SelectedFoldersVMWPF
    {
        get {return selectedFoldersVMWPF;}
        set {selectedFoldersVMWPF = value; OnPropertyChanged("SelectedFoldersVMWPF");}
    }
}
public分部类ViewCTRL:UserControld
{
公共静态从属属性SelectedFoldersProperty=
DependencyProperty.Register(“SelectedFolders”、typeof(ObservableCollection)、typeof(ViewCTRL),
新的FrameworkPropertyMetadata(){BindsTwoWayByDefault=true});
公共可观察集合选定文件夹
{
get{return(ObservableCollection)GetValue(SelectedFoldersProperty);}
set{SetValue(SelectedFoldersProperty,value);}
公共视图Ctrl()
{
var vm=新的ViewCTRLModel();
初始化组件();
GridMain.DataContext=vm;
//绑定
SetBinding(SelectedFoldersProperty,新绑定()
{
Source=GridMain.DataContext,
路径=新属性路径(“SelectedFoldersV”),
UpdateSourceTrigger=System.Windows.Data.UpdateSourceTrigger.PropertyChanged,
Mode=BindingMode.TwoWay
});
}
用户控件视图模型是:

<UserControl x:Class="TestDP.Views.ViewCTRL" [...]>
        <DataGrid Name="GridMain" ItemsSource="{Binding Folders}">
        <DataGrid.Columns>
            <DataGridCheckBoxColumn Header="Cked" Binding="{Binding Cked,  UpdateSourceTrigger=PropertyChanged}" />
            <DataGridTextColumn Header="Path" Binding="{Binding Path}"/>
        </DataGrid.Columns>
    </DataGrid>
</UserControl>
public partial class ViewCTRL : UserControld
{
    public static DependencyProperty SelectedFoldersProperty =
        DependencyProperty.Register("SelectedFolders", typeof(ObservableCollection<Folder>), typeof(ViewCTRL),
        new FrameworkPropertyMetadata() { BindsTwoWayByDefault = true });

    public ObservableCollection<Folder> SelectedFolders
    {
        get{return (ObservableCollection<Folder>)GetValue(SelectedFoldersProperty);}
        set{SetValue(SelectedFoldersProperty, value);}}

    public ViewCTRL()
    {
        var vm = new ViewCTRLModel();
        InitializeComponent();
        GridMain.DataContext = vm;

        // bindings
        SetBinding(SelectedFoldersProperty, new Binding()
        {
            Source = GridMain.DataContext,
            Path = new PropertyPath("SelectedFoldersV"),
            UpdateSourceTrigger =   System.Windows.Data.UpdateSourceTrigger.PropertyChanged,
            Mode = BindingMode.TwoWay
        });
    }
    public class ViewCTRLModel : INotifyPropertyChanged
{
    [...]

    public void Folder_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        SelectedFoldersV = new ObservableCollection<Folder>(Folders.Where(x => x.Cked));
    }

    private ObservableCollection<Folder> folders;
    public ObservableCollection<Folder> Folders
    {
        get{return folders;}
        set{folders = value;OnPropertyChanged("Folders");}
    }

    private ObservableCollection<Folder> selectedFoldersV;
    public ObservableCollection<Folder> SelectedFoldersV
    {
        get{return selectedFoldersV;}
        set{selectedFoldersV = value;OnPropertyChanged("SelectedFoldersV");}
    }
    [...]
}
class ViewWPFModel : INotifyPropertyChanged
{
    public ViewWPFModel()
    {
        SelectedFoldersVMWPF = new ObservableCollection<Folder>();
        SelectedFoldersVMWPF.Add(new Folder() { Path = "uuu" });
    }

    private ObservableCollection<Folder> selectedFoldersVMWPF;
    public ObservableCollection<Folder> SelectedFoldersVMWPF
    {
        get {return selectedFoldersVMWPF;}
        set {selectedFoldersVMWPF = value; OnPropertyChanged("SelectedFoldersVMWPF");}
    }
}
公共类ViewCTRLModel:INotifyPropertyChanged
{
[...]
公用无效文件夹\u PropertyChanged(对象发件人,PropertyChangedEventArgs e)
{
SelectedFoldersV=新的ObservableCollection(Folders.Where(x=>x.Cked));
}
私有可观察收集文件夹;
公共可观测集合文件夹
{
获取{返回文件夹;}
设置{folders=value;OnPropertyChanged(“folders”);}
}
私有可观测集合selectedFoldersV;
公共可观测集合选择的文件夹SV
{
获取{return selectedFoldersV;}
设置{selectedFoldersV=value;OnPropertyChanged(“selectedFoldersV”);}
}
[...]
}
然后,我使用一个WPF应用程序,在其中放置我的用户控件。如果我将用户控件DP SelectedFolders与ItemSource绑定,则一切正常。如果我选中用户控件的文件夹复选框,则SelectedFolder将在项目源上更新

<Window x:Class="TestDPWPF.Views.ViewWPF" [...]>
<uc:ViewCTRL Name="ViewCTRL" />
<ListBox ItemsSource="{Binding ElementName=ViewCTRL, Path=SelectedFolders}" DisplayMemberPath="Path"/>

如果我将SelectedFolders属性绑定到窗口视图模型的属性,如

<uc:ViewCTRL Name="ViewCTRL" SelectedFolders="{Binding SelectedFoldersVMWPF,  Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

用户控件获取由window viewmodel传递的初始值,但随后绑定似乎中断,选择任何文件夹都不会更新SelectedFoldersVMWPF绑定。

视窗的视图模型是:

<UserControl x:Class="TestDP.Views.ViewCTRL" [...]>
        <DataGrid Name="GridMain" ItemsSource="{Binding Folders}">
        <DataGrid.Columns>
            <DataGridCheckBoxColumn Header="Cked" Binding="{Binding Cked,  UpdateSourceTrigger=PropertyChanged}" />
            <DataGridTextColumn Header="Path" Binding="{Binding Path}"/>
        </DataGrid.Columns>
    </DataGrid>
</UserControl>
public partial class ViewCTRL : UserControld
{
    public static DependencyProperty SelectedFoldersProperty =
        DependencyProperty.Register("SelectedFolders", typeof(ObservableCollection<Folder>), typeof(ViewCTRL),
        new FrameworkPropertyMetadata() { BindsTwoWayByDefault = true });

    public ObservableCollection<Folder> SelectedFolders
    {
        get{return (ObservableCollection<Folder>)GetValue(SelectedFoldersProperty);}
        set{SetValue(SelectedFoldersProperty, value);}}

    public ViewCTRL()
    {
        var vm = new ViewCTRLModel();
        InitializeComponent();
        GridMain.DataContext = vm;

        // bindings
        SetBinding(SelectedFoldersProperty, new Binding()
        {
            Source = GridMain.DataContext,
            Path = new PropertyPath("SelectedFoldersV"),
            UpdateSourceTrigger =   System.Windows.Data.UpdateSourceTrigger.PropertyChanged,
            Mode = BindingMode.TwoWay
        });
    }
    public class ViewCTRLModel : INotifyPropertyChanged
{
    [...]

    public void Folder_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        SelectedFoldersV = new ObservableCollection<Folder>(Folders.Where(x => x.Cked));
    }

    private ObservableCollection<Folder> folders;
    public ObservableCollection<Folder> Folders
    {
        get{return folders;}
        set{folders = value;OnPropertyChanged("Folders");}
    }

    private ObservableCollection<Folder> selectedFoldersV;
    public ObservableCollection<Folder> SelectedFoldersV
    {
        get{return selectedFoldersV;}
        set{selectedFoldersV = value;OnPropertyChanged("SelectedFoldersV");}
    }
    [...]
}
class ViewWPFModel : INotifyPropertyChanged
{
    public ViewWPFModel()
    {
        SelectedFoldersVMWPF = new ObservableCollection<Folder>();
        SelectedFoldersVMWPF.Add(new Folder() { Path = "uuu" });
    }

    private ObservableCollection<Folder> selectedFoldersVMWPF;
    public ObservableCollection<Folder> SelectedFoldersVMWPF
    {
        get {return selectedFoldersVMWPF;}
        set {selectedFoldersVMWPF = value; OnPropertyChanged("SelectedFoldersVMWPF");}
    }
}
class ViewWPFModel:INotifyPropertyChanged
{
公共视图wpfmodel()
{
SelectedFoldersVMWPF=新的ObservableCollection();
选择edfoldersvmwpf.Add(新文件夹(){Path=“uuu”});
}
私有可观测集合选择FoldersVMWPF;
公共可观测集合选择的文件夹SVMWPF
{
获取{return selectedFoldersVMWPF;}
设置{selectedFoldersVMWPF=value;OnPropertyChanged(“selectedFoldersVMWPF”);}
}
}

我在输出窗口中没有关于绑定的任何消息,因此所有绑定路径都应该是正常的。我认为窗口视图模型和控件的DP之间的绑定被用户控件和用户控件视图模型之间的绑定破坏。但是我不知道为什么以及如何解决问题。我试图更改用户的DataContex控件,但结果总是一样的。任何人都可以将我引向正确的方向?

在第一个示例中,您已将ViewCTRL的SelectedFolders DependencyProperty绑定到ViewCTRLModel的SelectedFoldersV。然后,列表框的ItemsSource将绑定到SelectedFolders DependencyProperty

在第二个示例中,您已将ViewCTRL的SelectedFolders DependencyProperty绑定到ViewWPFModel的SelectedFoldersVMWPF属性(在ViewCTRL构造函数中的InitializeComponent()调用期间)。但紧接着,SetBindings调用将绑定更改为ViewCTRLModel的SelectedFoldersV

我以前没有这样做过,但我认为如果您将ViewModel中的SelectedFoldersV更改为DependencyProperty,并对ViewCTRL构造函数进行以下更改,则应该可以这样做:

    SetBinding(vm.SelectedFoldersVProperty, new Binding()
    {
        Source = this,
        Path = new PropertyPath("SelectedFolders"),
        UpdateSourceTrigger = System.Windows.Data.UpdateSourceTrigger.PropertyChanged,
        Mode = BindingMode.TwoWay
    });

请注意,可能有更好的方法来实现您正在尝试的操作(例如使用MVVM Light的Messenger在ViewModels之间传达这些更改)。我个人不想将一堆绑定链接在一起,因为我认为这会让人更加困惑。

欢迎使用Stack Overflow。作为将来的参考,您在这个问题中显示了太多的代码。在这个网站上,您应该向我们展示这些代码。这样做将帮助您和我们,并确保您能够快速获得答案-请注意,由于代码超载,您仍然没有收到一个答案。@puckk sheridan是对的…您的代码似乎混乱了…在您的usercontrol数据网格项中,当您的DP名称为Selected Folders时,源绑定到文件夹。为什么您需要在usercontrol构造函数中调用setbinding?稍微清理了代码…希望我现在更好:)。@nit Datagrid Itemsource绑定到用户控件viewmodel的文件夹。设置集合更改SelectedFoldersV时。在构造函数上设置绑定DP(SelectedFoldersProperty)选择用户控件viewmodel的适当性。用户控件VM上的dependency属性是一个非常好的尝试。实现了它,但不起作用。所有绑定似乎都可以,但VM上的DP不会通知后面代码上的DP。我不明白为什么。应该可以,但不行。因此,对于sug,我将使用MVVM Light.Thx手势。