I´m working on a project that uses Caliburn micro in wpf C#.
I´m in the process that I want to rewrite my method ReadMediaFile() so it displays all files in a folder in a list.
My method looks lite this:
private void ReadMediaFile()
{
string result;
_movieviewmodel = new MoviesViewModel();
string[] filePaths = Directory.GetFiles(#"C:/Users/v80770/Desktop/Movies/");
foreach (var file in filePaths)
{
result = Path.GetFileName(file);
_movieviewmodel.MovieName = result;
}
AddItem(_movieviewmodel);
}
When I debug the program all the files show in filePaths but only one shows in my list.
The AddItem is located in a class called TreeViewBase (belongs to caliburn micro I think) and it looks like this:
public void AddItem(T item)
{
_dispatcher.SmartInvoke(() => Items.Add(item));
}
I got the movie files viewing in my list but my MediaUri binding in view is bind against a specific path file but I want it to change dependent on what I choose
I tried to edit the binding to this:
string test = _movieviewmodel.MovieName;
MediaUri = new Uri(test);
But only get a exception "System.UriFormatException: 'Invalid URI: The format of the URI could not be determined.'"
Picture of Uri
New Uri code:
_movieviewmodel.MovieFilePath = #"C:/Users/v80770/Desktop/Movies/";
string test = _movieviewmodel.MovieFilePath;
MediaUri = new Uri(test + _movieviewmodel.MovieName);
But it always shows the same movie and my _movieviewmodel.MovieName does not change name dependent which movie I choose, it always is the same movie.
The creation of a MoviesViewModel item object and AddItem(_movieviewmodel); must be inside foreach, otherwise it would add only the last item:
foreach (var file in filePaths)
{
var movieviewmodel = new MoviesViewModel();
movieviewmodel.MovieName = Path.GetFileName(file);
AddItem(movieviewmodel);
}
or
foreach (var file in filePaths)
{
AddItem(new MoviesViewModel
{
MovieName = Path.GetFileName(file)
});
}
Related
My MediaPlaybackList.ShuffledItems has 10 items in it. But when I was trying to convert the items back to a list of ViewModel (in my case it is Music) using the uri, I got null.
Why is that? Is it because I load the file from my local drive?
This is how I get the uri:
public static async Task<List<Music>> GetRealPlayList()
{
if (PlayList.ShuffleEnabled)
{
if (ShuffledPlayList.Count == 0)
{
foreach (var music in PlayList.ShuffledItems)
{
ShuffledPlayList.Add(await Music.GetMusic(music.Source.Uri.AbsolutePath));
}
}
return ShuffledPlayList;
}
else
return CurrentPlayList;
}
This is how I set the items:
public static async Task SetPlayList(IEnumerable<Music> playlist)
{
if (Helper.SamePlayList(playlist, CurrentPlayList)) return;
PlayList.Items.Clear();
CurrentPlayList.Clear();
foreach (var music in playlist)
{
var item = new MediaPlaybackItem(MediaSource.CreateFromStorageFile(await Helper.CurrentFolder.GetFileAsync(music.GetShortPath())));
PlayList.Items.Add(item);
CurrentPlayList.Add(music);
}
}
What ways else can I convert the MediaPlackBackItem back to the ViewModel? The GetDisplayProperties().MusicProperties doesn't have the some properties that I want and the properties in it are also empty.
When you create MediaSource,you can set CustomProperties to save the file path in it.And when you loop through the PlayList.ShuffledItems,get file path from the CustomProperties.
Set the items:
MediaSource source = MediaSource.CreateFromStorageFile(await Helper.CurrentFolder.GetFileAsync(music.GetShortPath()));
source.CustomProperties.Add("Path", file.Path);
var item = new MediaPlaybackItem(source);
Get Music class:
foreach (var music in PlayList.ShuffledItems)
{
MediaSource source = music.Source;
String path = sour.CustomProperties["Path"].ToString();
ShuffledPlayList.Add(await Music.GetMusic(path));
}
Information given
I am using version 16.0.0.0 of the Microsoft.SharePoint.Client library.
There are several different document libraries in the SharePoint site. In code, we are given a list of document URLs (containing document GUIDs) and need to determine in which Document Library each is located, including the sub-folder if it is in a folder in the library.
Document Id (GUID) - gathered from document url query parameter "sourcedoc"
ex: "http://mycompany.sharepoint.com/spsite/_layouts/15/WopiFrame.aspx?action=default&file=testfile.docx&sourcedoc={6A290A65-4759-41ED-A13E-3333B45DF133}"
Information needed
Document Library Name
Document Library URL
Folder Name (if any)
Folder URL (if any)
Current Code
using SP = Microsoft.SharePoint.Client;
public class LibraryAndFolderInfo
{
public LibraryAndFolderInfo();
public string FolderName { get; set; }
public string FolderUrl { get; set; }
public string LibraryName { get; set; }
public string LibraryBaseUrl { get; set; }
}
public class SPDataAccess
{
public LibraryAndFolderInfo GetLibraryAndFolderInfo(Guid documentGuid)
{
SP.File file = Web.GetFileById(documentGuid);
Context.Load(file);
if (file != null)
{
Context.Load(file.ListItemAllFields);
Context.ExecuteQuery();
SP.ListItem item = file.ListItemAllFields;
Context.Load(item.ParentList);
Context.ExecuteQuery();
SP.List list = item.ParentList;
Context.Load(list);
Context.ExecuteQuery();
Context.Load(item.Folder);
Context.ExecuteQuery();
SP.Folder folder = item.Folder;
Context.Load(folder);
Context.ExecuteQuery();
LibraryAndFolderInfo lib = new LibraryAndFolderInfo();
lib.LibraryName = list.Title;
lib.LibraryBaseUrl = list.DefaultViewUrl;
lib.FolderName = folder.Name;
lib.FolderUrl = folder.ServerRelativeUrl;
return lib;
}
return null;
}
protected SP.ClientContext Context { get; set; }
}
The code currently fails at this line: Context.Load(item.ParentList); with the following error:
The property or field 'Title' has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested.
at Microsoft.SharePoint.Client.ClientObject.CheckUninitializedProperty(String propName)
at Microsoft.SharePoint.Client.List.get_Title()
at MyNamespace.SPDataAccess.GetLibraryAndFolderInfo(Guid documentGuid) in c:\path\SPDataAccess.cs:line 27
This line seems to be attempting to retrieve the Title of the list as it is being loaded and failing. Is this a correct assumption?
I am not super familiar with how exactly to load properties, so everything after the failing line is my best guess as to how it would work.
What is this code supposed to look like? Has anyone else tried to get this information from a document?
Below are provided some corrections, fixes and considerations for your code:
1)The condition if (file != null) is incorrect since it could not be used to determine whether file exists or not. The following example demonstrates how to verify whether file has been loaded:
SP.File file = Context.Web.GetFileById(documentGuid);
Context.Load(file);
Context.ExecuteQuery();
if (file.ServerObjectIsNull != null)
{
//File has been loaded..
}
2)item.Folder does not return parent Folder, it returns Folder associated with List Item and it is not the same
How to return parent Folder for a File?
var file = Context.Web.GetFileById(documentGuid);
Context.Load(file,i => i.ListItemAllFields);
Context.ExecuteQuery();
var folder = Context.Web.GetFolderByServerRelativeUrl((string)file.ListItemAllFields["FileDirRef"]);
Context.Load(folder);
Context.ExecuteQuery();
3)List.DefaultViewUrl returns a default view server relative url and it is not the same as List server relative url
How to retrieve List Url?
var file = Context.Web.GetFileById(documentGuid);
var item = file.ListItemAllFields;
Context.Load(item.ParentList, l => l.RootFolder);
Context.ExecuteQuery();
var listUrl = item.ParentList.RootFolder.ServerRelativeUrl;
4)Since SharePoint CSOM supports Request Batching there is no need to submit multiple queries, instead you could submit only a single query as demonstrated below:
SP.File file = Context.Web.GetFileById(documentGuid);
SP.ListItem item = file.ListItemAllFields;
var list = item.ParentList;
Context.Load(list, l => l.Title, l => l.RootFolder);
Context.Load(item);
Context.ExecuteQuery(); //<- submit a single batch query
Fixed example
public class SPDataAccess
{
public SPDataAccess(SP.ClientContext ctx)
{
Context = ctx;
}
public LibraryAndFolderInfo GetLibraryAndFolderInfo(Guid documentGuid)
{
var file = Context.Web.GetFileById(documentGuid);
var item = file.ListItemAllFields;
var list = item.ParentList;
Context.Load(list, l => l.Title, l => l.RootFolder);
Context.Load(item);
Context.ExecuteQuery();
var info = new LibraryAndFolderInfo();
var folderUrl = (string)item["FileDirRef"];
info.LibraryName = list.Title; //list title
info.LibraryBaseUrl = list.RootFolder.ServerRelativeUrl; //list url
if (folderUrl.Replace(list.RootFolder.ServerRelativeUrl, string.Empty).Length > 0)
{
info.FolderName = folderUrl.Split('/').Last(); //folder name
info.FolderUrl = folderUrl;
}
return info;
}
protected SP.ClientContext Context { get; private set; }
}
I have a combobox which gets the list of items from the name of files I put together in one directory, the purpose for this is to make it dynamic - I'm very new to c# and it didn't occur to me a different way. - Here's the code for that bit:
string[] files = Directory.GetFiles(templatePath);
foreach (string file in files)
cbTemplates.Items.Add(System.IO.Path.GetFileNameWithoutExtension(file));
Basically, that works just fine, it populates my combobox with the names of the files I have in that path, the problem is that I need to open the file that's selected in the combobox and read its contents and place them in labels, I was thinking maybe StreamReader would help me here but I have NO clue on how to implement it, I've searched the internet but it looks like no one had the same idea before me. Can someone please point me in the right direction? A link to something similar or a guide of the objects I need to use would be great, thanks!
what you should do is store the names of the files in a single separate file (csv or xml). then use this file to both load the combobox and as an indexer.
for example lets say you have files a.txt, b.txt, and c.txt. you should (as you already are) read the file names programmatically THEN write them to a new file in whichever format you want, including a unique index scheme (numbers work fine).
your csv might look like this:
1, a.txt,
2, b.txt,
3, c.txt,
from here you can parse the newly created csv to your liking. Use it to populate your combobox, index being its value and filename its text. Then you can read your combobox selectedvalue, get the proper filename from the csv index, and finally open the file.
It may be longwinded but it'll work. You could also just use a multidimensional array, but this is more fun from an educational stand point, and it will help you with read/write operations.
It is not so easy to understand your problem. Do you want just to display filename w/o extension in your combobox? I hope this code will be usefull to you.
internal class FileDetail
{
public string Display { get; set; }
public string FullName { get; set; }
}
public partial class Example: Form // This is just widows form. InitializeComponent is implemented in separate file.
{
public Example()
{
InitializeComponent();
filesList.SelectionChangeCommitted += filesListSelectionChanged;
filesList.Click += filesListClick;
filesList.DisplayMember = "Display";
}
private void filesListClick(object sender, EventArgs e)
{
var dir = new DirectoryInfo(_baseDirectory);
filesList.Items.AddRange(
(from fi in dir.GetFiles()
select new FileDetail
{
Display = Path.GetFileNameWithoutExtension(fi.Name),
FullName = fi.FullName
}).ToArray()
);
}
private void filesListSelectionChanged(object sender, EventArgs e)
{
var text = File.ReadAllText(
(filesList.SelectedItem as FileDetail).FullName
);
fileContent.Text = text;
}
private static readonly string _baseDirectory = #"C:/Windows/System32/";
}
Thanks for all your help folks but I figured out how to get around my issue, I'll post the code for future incidents. pd. Sorry it took me this long to reply, I was on vacation
string[] fname = Directory.GetFiles(templatePath); // Gets all the file names from the path assigned to templatePath and assigns it to the string array fname
// Begin sorting through the file names assigned to the string array fname
foreach (string file in fname)
{
// Remove the extension from the file names and compare the list with the dropdown selected item
if (System.IO.Path.GetFileNameWithoutExtension(file) != cbTemplates.SelectedItem.ToString())
{
// StreamReader gets the contents from the found file and assigns them to the labels
using (var obj = new StreamReader(File.OpenRead(file)))
{
lbl1.Content = obj.ReadLine();
lbl2.Content = obj.ReadLine();
lbl3.Content = obj.ReadLine();
lbl4.Content = obj.ReadLine();
lbl5.Content = obj.ReadLine();
lbl6.Content = obj.ReadLine();
lbl7.Content = obj.ReadLine();
lbl8.Content = obj.ReadLine();
lbl9.Content = obj.ReadLine();
lbl10.Content = obj.ReadLine();
obj.Dispose();
}
}
}
On my FTP Server I have the following folder structure
- Parent Directory
-a.txt
-b.txt.old
-SubDirectory1
-c.txt
-NestedSubDirectory1
-d.txt
-SubDirectory2
-e.txt
-f.txt.old
The number of SDs are not fixed. I need a way to get all the files(can be any format) without the .old extension from the Parent Directory.
I'm currently using the 3rd party dll edtFTPnet.
ftpConnection.GetFileInfos()Where(f => !(f.Name.EndsWith(".old"))).ToList();
This helps me get the details of the files and folders at the current working directory level.
Can someone tell me a way to get all the files with the parentdirectory, subdirectories and nested subdirectories.
The solution may or may not use edtFTPnet.
FTPConnection.GetFileInfos() returns an array of FTPFile. The class FTPFile has a boolean property Dir which indicates whether its filename accesses a file (false) or directory (true).
Something like this should work:
void ReadSubDirectories(FTPConncetion connection, FTPFile[] files)
{
foreach (var file in files)
{
if (file.Dir)
{
// Save parent directory
var curDir = connection.ServerDirectory;
// Move into directory
connection.ChangeWorkingDirectory(file.Name)
// Read all files
ReadSubDirectories(connection, connection.GetFileInfos());
// Move back into parent directory
connection.ChangeWorkingDirectory(curDir)
}
else
{
// Do magic with your files
}
}
}
However you might be better off using just .NET's built-in FtpWebRequest class since its methods and naming conventions are clearer, it's better documented and it's easier to find references online.
Try to use extensions like this:
class Program
{
static void Main(string[] args)
{
using (var connection = new FTPConnection
{
ServerAddress = "127.0.0.1",
UserName = "Admin",
Password = "1",
})
{
connection.Connect();
connection.ServerDirectory = "/recursive_folder";
var resultRecursive =
connection.GetFileInfosRecursive().Where(f => !(f.Name.EndsWith(".old"))).ToList();
var resultDefault = connection.GetFileInfos().Where(f => !(f.Name.EndsWith(".old"))).ToList();
}
}
}
public static class FtpClientExtensions
{
public static FTPFile[] GetFileInfosRecursive(this FTPConnection connection)
{
var resultList = new List<FTPFile>();
var fileInfos = connection.GetFileInfos();
resultList.AddRange(fileInfos);
foreach (var fileInfo in fileInfos)
{
if (fileInfo.Dir)
{
connection.ServerDirectory = fileInfo.Path;
resultList.AddRange(connection.GetFileInfosRecursive());
}
}
return resultList.ToArray();
}
}
In Sharepoint how can you copy a list item from one list to another list
eg copy from "List A" to "List B" (both are at the root of the site)
I want this copying to occur when a new list item is added to "List A"
I tried using the CopyTo() method of an SPListItem inside the ItemAdded event receiver but couldnt figure out the url to copy to.
Here is the code I use. Pass it a SPlistItem and the name of the destination list as seen in Sharepoint(Not the URL). The only restriction is that both list must be in the same site:
private SPListItem CopyItem(SPListItem sourceItem, string destinationListName) {
//Copy sourceItem to destinationList
SPList destinationList = sourceItem.Web.Lists[destinationListName];
SPListItem targetItem = destinationList.Items.Add();
foreach (SPField f in sourceItem.Fields) {
//Copy all except attachments.
if (!f.ReadOnlyField && f.InternalName != "Attachments"
&& null != sourceItem[f.InternalName])
{
targetItem[f.InternalName] = sourceItem[f.InternalName];
}
}
//Copy attachments
foreach (string fileName in sourceItem.Attachments) {
SPFile file = sourceItem.ParentList.ParentWeb.GetFile(sourceItem.Attachments.UrlPrefix + fileName);
byte[] imageData = file.OpenBinary();
targetItem.Attachments.Add(fileName, imageData);
}
return targetItem;
}
Indeed as Lars said, it can be tricky to move items and retain versions and correct userinfo. I have done similar things with that before so if you need some code examples, let me know through a comment and can supply you with some guidance.
The CopyTo method (if you decide to go with that) need an absolute Uri like:
http://host/site/web/list/filename.doc
So, if you are performing this in an event receiver you need to concatinate a string containing the elements needed. Something like (note that this can be done in other ways to):
string dest=
siteCollection.Url + "/" + site.Name + list.Name + item.File.Name;
Copying and moving files, items and folders in SharePoint can be tricky if you want to retain all metadata, timestamps, author info and version history. Take a look a CopyMove for SharePoint - it also has a Web Service API.
There's many tools on the market for copying a list item to another list (avepoint, metavis, etc.) but they are pretty expensive if you're planning to do this on only one list.
If you can do this manually once a week for example, look at the following tool : http://en.share-gate.com/sharepoint-tools/copy-move-sharepoint-list-items-with-metadata-and-version-history
Here is a powershell equivalent of Sylvian's that does allow for cross-site copy. His code could be modified similarly as well...
param([string]$sourceWebUrl, [string]$sourceListName, [string]$destWebUrl, [string]$destListName)
$sourceWeb = get-spweb $sourceWebUrl;
$sourceList = $sourceWeb.Lists[$sourceListName];
$destWeb = get-spweb $destWebUrl;
$destList = $destWeb.Lists[$destListName];
$sourceList.Items |%{
$destItem = $destList.Items.Add();
$sourceItem = $_;
$sourceItem.Fields |%{
$f = $_;
if($f.ReadOnlyField -eq $false -and $f.InternalName -ne "Attachments" -and $sourceItem[$f.InternalName] -ne $null){
$destItem[$f.InternalName] = $sourceItem[$f.InternalName];
}
}
$destItem.Update();
}
To use, copy and past to a file copy-listitems.ps1 and run using Sharpoint powerhsell commandline...
Make sure you call CopyTo(url) method on SPFile, not on SPListItem.
for example:
ItemUpdated(SPItemEventProperties properties)
{
//...
string url = properties.Web.Site.Url + "/" + properties.Web.Name + "Lists/ListName/" + properties.ListItem.File.Name;
//properties.ListItem.File.MoveTo(url);
properties.ListItem.File.CopyTo(url);
//...
}
private void CopyAttachmentsToList(SPListItem srcItem, SPListItem tgtItem)
{
try
{
//get source item attachments from the folder
SPFolder srcAttachmentsFolder =
srcItem.Web.Folders["Lists"].SubFolders[srcItem.ParentList.Title].SubFolders["Attachments"].SubFolders[srcItem.ID.ToString()];
//Add items to the target item
foreach (SPFile file in srcAttachmentsFolder.Files)
{
byte[] binFile = file.OpenBinary();
tgtItem.Update();
tgtItem.Attachments.AddNow(file.Name, binFile);
tgtItem.Update();
}
}
catch
{
//exception message goes here
}
finally
{
srcItem.Web.Dispose();
}
}
Don't forget to add this line, tgtItem.Update();, else you will get an err.
So, the lists have the exact same or similar columns? Either way, you could create a simple workflow that runs automatically when an item is created in "List A". Since the workflow in question is relatively simple, I'd recommend using SharePoint Designer (which is free) to create it, since you can easily match up the columns from the two lists. The walk through below should be able to help you get started.
Create a Workflow - SharePoint Designer
I had the same problem.
After experimenting a bit instead of
targetItem[f.InternalName] = sourceItem[f.InternalName];
I used:
targetItem[childField.Title] = sourceItem[parentField.Title];
How to copy field and save versions:
public static SPListItem CopyItem(SPListItem sourceItem, SPList destinationList)
{
SPListItem targetItem = destinationList.AddItem();
//loop over the soureitem, restore it
for (int i = sourceItem.Versions.Count - 1; i >= 0; i--)
{
//set the values into the archive
foreach (SPField sourceField in sourceItem.Fields)
{
SPListItemVersion version = sourceItem.Versions[i];
if ((!sourceField.ReadOnlyField) && (sourceField.InternalName != "Attachments"))
{
SetFields(targetItem, sourceField, version);
}
}
//update the archive item and
//loop over the the next version
targetItem.Update();
}
foreach (string fileName in sourceItem.Attachments)
{
SPFile file = sourceItem.ParentList.ParentWeb.GetFile(sourceItem.Attachments.UrlPrefix + fileName);
targetItem.Attachments.Add(fileName, file.OpenBinary());
}
targetItem.SystemUpdate();
return targetItem;
}
private static bool SetFields(SPListItem targetItem, SPField sourceField, SPListItemVersion version)
{
try
{
targetItem[sourceField.InternalName] = version.ListItem[sourceField.InternalName];
return true;
}
catch (System.ArgumentException)//field not filled
{
return false;
}
catch (SPException)//field not filled
{
return false;
}
}
Copy List Items from one SharePoint List or library to Another SharePoint list or library using c# server side code
//Itecollection is a collection of data from source list
public void CopyItemsFromOneListToAnotherList(SPListItemCollection itemCollection)
{
using (SPSite site = new SPSite(siteUrl))
{
using (SPWeb web = site.OpenWeb())
{
//Get destination list/library
//destListName - Destination list/library name
SPList destList = web.Lists.TryGetList(destListName);
foreach (SPListItem sourceItem in itemCollection)
{
//Add new Item to list
SPListItem destItem = destList.Items.Add();
foreach (SPField field in sourceItem.Fields)
{
if (!field.ReadOnlyField && !field.Hidden && field.InternalName != "Attachments")
{
if (destItem.Fields.ContainsField(field.InternalName))
{
//Copy item to destination library
destItem[field.InternalName] = sourceItem[field.InternalName];
}
}
}
//Update item in destination library or list
destItem.Update();
Console.WriteLine("Copied " + sourceItem["ID"] + "to destination list/library");
}
}
}
}