0

我开始使用 MVVM(使用 Caliburn.Micro)并且遇到了一个我不确定我是否正确执行此操作的问题。我有一个模型MediaCacherConfig,它代表一个以 json 格式存储数据的文本文件。该模型包含 2 个字符串列表和一个单独的字符串。

我正在努力解决的是如何正确设置视图模型,尤其是AddNewFolder()方法。我不确定我是否提出了正确的事件以及视图模型的表示是否正确。我可以看到如何绑定到一个简单的属性,但是绑定到一个集合似乎更令人头疼,因为每次添加项目(字符串)时我都会创建一个全新的集合。

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

非常感谢任何指导。

public class MediaCacherConfig : IConfig
{

    public string DatabaseFileName { get; set; }

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

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

}

我有一个视图模型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>

4

1 回答 1

2

首先,在这里你每次都返回一个全新的集合,所以显然没有任何东西被持久化。

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

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


我就是这样做的。这显然是用于演示目的的示例,请添加您需要的所有其他内容。Youd ideall 希望通过EventArgs并注意我没有实施INotifyPorpertyChanged,因为我没有时间把它全部写出来。我也在使用ObservableCollection,但你可以使用你的BindableCollection.

这个例子的重点是向您展示如何管理您的 ViewModel -> Model 通信。从技术上讲,您的 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);
        }
    }
于 2012-12-07T18:51:38.000 回答