首页 文章

绑定到包含MVVM中的集合的模型

提问于
浏览
0

我开始使用MVVM(使用Caliburn.Micro)并遇到了一个问题,我正确地做了这个 . 我有一个模型 MediaCacherConfig ,它表示以json格式存储数据的文本文件 . 该模型包含2个字符串列表和一个字符串 .

我正在努力的是如何正确设置viewmodel,特别是 AddNewFolder() 方法 . 我'm not sure if I am raising the correct event and whether the viewmodel'的表示是正确的 . 我可以看到如何绑定到一个简单的属性,但绑定到一个集合看起来更像一个头部微调器,因为我每次添加一个项目(字符串)时创建一个全新的集合 .

此外,当我加载一个全新的模型时,我必须对所有对我没有意义的属性运行NotifyPropertyChanged()方法 .

任何指导都非常感谢 .

public class MediaCacherConfig : IConfig
{

    public string DatabaseFileName { get; set; }

    public ICollection<string> FoldersToScan { get; set; }

    public ICollection<string> ExtensionsToIgnore { get; set; }

}

我有一个viewmodel MediaCacherConfigViewModel

public class MediaCacherConfigViewModel : PropertyChangedBase
{

    private MediaCacherConfig Model { get; set; }

    public string DatabaseFileName
    {
        get { return Model.DatabaseFileName; }
        set
        {
            Model.DatabaseFileName = value;
            NotifyOfPropertyChange(() => DatabaseFileName);
        }
    }

    public BindableCollection<string> FoldersToScan
    {
        get
        {
            return new BindableCollection<string>(Model.FoldersToScan);
        }
        set
        {
            Model.FoldersToScan = value;
            NotifyOfPropertyChange(() => FoldersToScan);
        }
    }

    public BindableCollection<string> ExtensionsToIgnore
    {
        get
        {
            return new BindableCollection<string>(Model.ExtensionsToIgnore);
        }
        set
        {
            Model.ExtensionsToIgnore = value;
            NotifyOfPropertyChange(() => ExtensionsToIgnore);
        }
    }

    /* Constructor */
    public MediaCacherConfigViewModel()
    {
        LoadSampleConfig();
    }

    /* Methods */
    public void LoadSampleConfig()
    {

        MediaCacherConfig c = new MediaCacherConfig();

        string sampleDatabaseFileName = "testing.config";

        List<string> sampleFoldersToScan = new List<string>();
        sampleFoldersToScan.Add("A");
        sampleFoldersToScan.Add("B");
        sampleFoldersToScan.Add("C");

        List<string> sampleExtensionsToIgnore = new List<string>();
        sampleExtensionsToIgnore.Add("txt");
        sampleExtensionsToIgnore.Add("mov");
        sampleExtensionsToIgnore.Add("db");
        sampleExtensionsToIgnore.Add("dat");

        c.DatabaseFileName = sampleDatabaseFileName;
        c.FoldersToScan = sampleFoldersToScan;
        c.ExtensionsToIgnore = sampleExtensionsToIgnore;

        Model = c;

        NotifyOfPropertyChange(() => DatabaseFileName);
        NotifyOfPropertyChange(() => FoldersToScan);
        NotifyOfPropertyChange(() => ExtensionsToIgnore);


    }

    public void AddNewFolder()
    {
        Model.FoldersToScan.Add("new one added");
        NotifyOfPropertyChange(() => FoldersToScan);

    }

    public void SaveConfig()
    {
        ConfigTools.Configure(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Cacher", "Config"));

        ConfigTools.SaveConfig(Model,"sampleconfig.txt");              
    }

    public void LoadConfig()
    {
        ConfigTools.Configure(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Cacher", "Config"));

        MediaCacherConfig m = ConfigTools.LoadConfig<MediaCacherConfig>("sampleconfig.txt") as MediaCacherConfig;
        Model = m;


        NotifyOfPropertyChange(() => DatabaseFileName);
        NotifyOfPropertyChange(() => FoldersToScan);
        NotifyOfPropertyChange(() => ExtensionsToIgnore);

    }
}

这是我的观点:

<UserControl x:Class="MediaCacher.Views.MediaCacherConfigView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="413" Width="300">
<Grid MinWidth="300" MinHeight="300" Background="LightBlue" Margin="0,0,0,0">
    <Grid.RowDefinitions>
        <RowDefinition Height="409*"/>
        <RowDefinition Height="4*"/>
    </Grid.RowDefinitions>
    <TextBox x:Name="DatabaseFileName" TextWrapping="Wrap" Margin="10,64,10,0" HorizontalAlignment="Center" Width="280" Height="42" VerticalAlignment="Top"/>
    <ListBox x:Name="FoldersToScan" HorizontalAlignment="Left" Height="145" Margin="10,111,0,0" VerticalAlignment="Top" Width="280"/>
    <ListBox x:Name="ExtensionsToIgnore" HorizontalAlignment="Left" Height="145" Margin="10,261,0,0" VerticalAlignment="Top" Width="280"/>
    <Button x:Name="AddNewFolder" Content="Add" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="87" Height="49"/>
    <Button x:Name="LoadConfig" Content="Load" HorizontalAlignment="Left" Margin="102,10,0,0" VerticalAlignment="Top" Width="96" Height="49"/>
    <Button x:Name="SaveConfig" Content="Save" HorizontalAlignment="Left" Margin="203,10,0,0" VerticalAlignment="Top" Width="87" Height="49"/>
</Grid>

1 回答

  • 2

    首先,这里每次都会返回一个全新的系列,所以很明显没有任何东西可以保留 .

    public BindableCollection<string> FoldersToScan
        {
            get
            {
                return new BindableCollection<string>(Model.FoldersToScan);
            }
            set
            {
                Model.FoldersToScan = value;
                NotifyOfPropertyChange(() => FoldersToScan);
            }
        }
    

    其次,您的AddFolder方法应该属于您的ViewModel . 当您将字符串添加到现有集合时,它是BindingCollection的事实应该自动向View发起一个事件,即添加了一个新项目 .


    我就是这样做的 . 这显然是一个用于演示目的的示例,请添加您需要的其他所有内容 . 你想要传递 EventArgs 并注意我没有实现 INotifyPorpertyChanged ,因为我没有时间把它写出来 . 我也在使用 ObservableCollection 但您可以使用 BindableCollection .

    这个例子的目的是向您展示如何管理您的ViewModel - >模型通信 . 从技术上讲,您的View - > ViewModel应该通过CommandPattern进行通信 .

    public class YourViewModel
        {
            private readonly YourModel model;
            private ObservableCollection<string> foldersToScan = new ObservableCollection<string>();
            public ObservableCollection<string> FoldersToScan
            {
                get { return this.foldersToScan; }
            }
    
            public YourViewModel(YourModel model)
            {
                this.model = model;
                this.model.OnItemAdded += item => this.foldersToScan.Add(item);
            }
    
            public void AddFolder(string addFolder) //gets called from view
            {
                this.model.AddFolder(addFolder); //could be ICommand using Command Pattern
            }
        }
    
        public class YourModel
        {
            private readonly List<string> foldersToScan;
            public IEnumerable<string>  FoldersToScan
            {
                get { return this.foldersToScan; }
            }
    
    
            public event Action<string> OnItemAdded; 
    
            public YourModel()
            {
                this.foldersToScan = new List<string>();
            }
    
            public void AddFolder(string folder)
            {
                this.foldersToScan.Add(folder);
                this.RaiseItemAdded(folder);
            }
    
            void RaiseItemAdded(string folder)
            {
                Action<string> handler = OnItemAdded;
                if (handler != null) handler(folder);
            }
        }
    

相关问题