【问题标题】:Updating ObservableCollection in ViewModel from dropped files in ListBox in the view - WPF从视图中 ListBox 中删除的文件更新 ViewModel 中的 ObservableCollection - WPF
【发布时间】:2017-10-09 18:43:18
【问题描述】:

我正在尝试了解如何在用户控件的列表框中处理拖放的文件,并绑定它们以更新我的 ViewModel 中的 ObservableCollection。

这是我在 XAML 中的列表框:

    <ListBox x:Name="listDrop" Height="50" Margin="0,0,0,0"  AllowDrop="True" Drop="dropfiles"  >

    </ListBox>

现在是代码隐藏:

public partial class ProcessXML : UserControl
{


    public ProcessXML()
    {
        InitializeComponent();


    }

    private void dropfiles(object sender, DragEventArgs e)
    {


        string[] droppedFiles = null;

        if (e.Data.GetDataPresent(DataFormats.FileDrop))
        {
            droppedFiles = e.Data.GetData(DataFormats.FileDrop, true) as string[];
        }

        if ((null == droppedFiles) || (!droppedFiles.Any())) { return; }

        listDrop.Items.Clear();

        foreach (string s in droppedFiles)
        {
            listDrop.Items.Add(s);
        }


    }
}

这列出了要删除的文件的路径,工作正常,但是我如何发送该信息或使用它来处理它?

我想将此数据发送到我的 Viewmodel,理想情况下发送到 ObservableCollection,然后处理每个项目,但我一直在摸不着头脑,找不到方法。我将如何做到这一点?

【问题讨论】:

  • EventToCommand ?
  • 它不起作用,因为在视图模型中无法识别 eventargs e,如果我错过了什么,你能以某种方式详细说明吗?谢谢
  • 看看我的回答。

标签: c# wpf xaml mvvm listbox


【解决方案1】:

您的代码中没有任何内容表明您甚至有一个视图模型,或者您将它用于什么。我将假设——错误地,我怀疑——这是用户控件的DataContext

如果您希望您的视图模型在文件被删除时执行某些操作,您可以让它处理其DropFiles 集合的CollectionChanged 事件,或者您可以给它一个方法让文件删除处理程序调用。

private void dropfiles(object sender, DragEventArgs e)
{
    string[] droppedFiles = null;

    if (e.Data.GetDataPresent(DataFormats.FileDrop))
    {
        droppedFiles = e.Data.GetData(DataFormats.FileDrop, true) as string[];
    }


    if ((null == droppedFiles) || (!droppedFiles.Any())) { return; }

    var myVM = DataContext as MyViewModel;

    //   MyViewModel.DropFiles should be ObservableCollection<String>
    myVM.DropFiles.Clear();

    foreach (string s in droppedFiles)
    {
        myVM.DropFiles.Add(s);
    }
}

替代:

private void dropfiles(object sender, DragEventArgs e)
{
    string[] droppedFiles = null;

    if (e.Data.GetDataPresent(DataFormats.FileDrop))
    {
        droppedFiles = e.Data.GetData(DataFormats.FileDrop, true) as string[];
    }


    if ((null == droppedFiles) || (!droppedFiles.Any())) { return; }

    var myVM = DataContext as MyViewModel;

    myVM.DoFileDrop(droppedFiles);
}

MyViewModel.cs

public void DoFileDrop(IEnumerable<String> filePaths)
{
    DropFiles.Clear();
    foreach (var s in filePaths)
        DropFiles.Add(s);

    //  Do other stuff if you want to
}

XAML

<ListBox 
    x:Name="listDrop" 
    Height="50" 
    Margin="0,0,0,0"  
    AllowDrop="True" 
    Drop="dropfiles"  
    ItemsSource="{Binding DropFiles}"
    />

【讨论】:

  • 谢谢!那成功了。我缺少的明显部分是如何访问我的 Datacontext 实例,但是 var myVM = DataContext as MyViewModel;是需要的!
  • 我相信我做到了,但不确定你是否能看到它,因为我是这里的菜鸟 :)
【解决方案2】:

如果您将 ViewModel 绑定到 ProcessXMLDataContext,那么您可以像这样访问您的 ViewModel

private void dropfiles(object sender, DragEventArgs e)
{
    // some code goes here ...


    var vm = this.DataContext as ViewModelType;
    if (vm == null) return;

    // Do your stuff with vm instance below
}

已编辑

我想你想要这样的东西:

<Window x:Name="root">
    <Grid x:Name="someParentControl">
        <controls:ProcessXML ParentViewModel={Binding Path=DataContext, ElementName=root}/>
    </Grid>
</Window>

还有ProcessXML背后的代码

public partial class ProcessXML : UserControl
{
    public ProcessXML()
    {
        InitializeComponent();
    }

    DependencyProperty ParentViewModelProperty = DependencyProperty
        .Register("ParentViewModel", typeof(ViewModelType), typeof(ProcessXML), new PropertyMetadata(null));

    public ViewModelType ParentViewModel
    {
        get { return (ViewModelType)GetValue(ParentViewModelProperty); }
        set { SetValue(ParentViewModelProperty, value); }
    }
}

【讨论】:

  • 如果您没有明确设置,您的用户控件 ProcessXML 也有可能继承其父级的 DataContext
  • 谢谢,但我应该把这个放在哪里?我尝试将其插入 ProcessXML UserControl 中,但没有成功。我应该把它放在用户控件的构造函数中吗?
  • @jayNorth “不起作用”是什么意思?请解释发生了什么问题。
  • 这工作 TEИ。开发人员,我没有将 var vm = this.DataContext 写为 ViewModelType;正确,但现在没关系。谢谢。
【解决方案3】:

以下是使用MvvmLightLibs 实现该目标的方法:

  • ObservableCollection&lt;T&gt;
  • EventToCommand

窗口 XAML:

<Window
    x:Class="WpfApp1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:wpfApp1="clr-namespace:WpfApp1"
    d:DataContext="{d:DesignInstance wpfApp1:Model}"
    mc:Ignorable="d">
    <Window.DataContext>
        <wpfApp1:Model />
    </Window.DataContext>

    <Grid>
        <wpfApp1:UserControl1 />
    </Grid>
</Window>

窗口代码:

namespace WpfApp1
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

用户控制 XAML:

<UserControl
    x:Class="WpfApp1.UserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:command="http://www.galasoft.ch/mvvmlight"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:local="clr-namespace:WpfApp1"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    d:DataContext="{d:DesignInstance local:Model}"
    mc:Ignorable="d">
    <Grid>
        <ListBox AllowDrop="True" ItemsSource="{Binding Files}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Drop">
                    <command:EventToCommand Command="{Binding Load}" PassEventArgsToCommand="True" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </ListBox>
    </Grid>
</UserControl>

用户控制代码:

namespace WpfApp1
{
    public partial class UserControl1
    {
        public UserControl1()
        {
            InitializeComponent();
        }
    }
}

型号:

using System.Collections.ObjectModel;
using System.Windows;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.CommandWpf;

namespace WpfApp1
{
    public class Model : ViewModelBase
    {
        public Model()
        {
            Files = new ObservableCollection<string>();

            Load = new RelayCommand<DragEventArgs>(e =>
            {
                var files = e.Data.GetData(DataFormats.FileDrop) as string[];
                if (files == null)
                    return;

                foreach (var file in files)
                {
                    Files.Add(file);
                }
            });
        }

        public RelayCommand<DragEventArgs> Load { get; }

        public ObservableCollection<string> Files { get; }
    }
}

这是一个简单的示例,显然您需要根据自己的需要对其进行进一步调整。

【讨论】:

  • 我不知道我可以通过这种方式传递事件参数,这很好用,谢谢!
  • 如果我的回答让您满意,请考虑接受或投票:)
  • 我投了赞成票,但由于我还是新手,所以没有显示出来(我猜是代表点数不够?)
猜你喜欢
  • 2021-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-26
  • 1970-01-01
  • 2014-03-08
  • 2011-08-25
  • 1970-01-01
相关资源
最近更新 更多