In My WPF App i have some pages, and I need to check for example:
new Uri("Pages/Page2.xaml", UriKind.Relative)
exist or not, I tried somethig semilar to this, just from Absolute replaced to Relative
bool IsRelativeUrl(string url)
{
Uri result;
return Uri.TryCreate(url, UriKind.Relative, out result);
}
Then Is printed:
string url = "Pages/Page2.xaml";
MessageBox.Show(IsRelativeUrl(url).ToString());
And it says always true, even for non existing pages
You can't use an Uri to determine whether a resource exists. You need to look for the compiled BAML resource:
bool IsRelativeUrl(string url)
{
Assembly assembly = Assembly.GetExecutingAssembly();
string[] resources = assembly.GetManifestResourceNames();
//Stream bamlStream = null;
foreach (string resourceName in resources)
{
ManifestResourceInfo info = assembly.GetManifestResourceInfo(resourceName);
if (info.ResourceLocation != ResourceLocation.ContainedInAnotherAssembly)
{
using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName))
using (ResourceReader reader = new ResourceReader(resourceStream))
{
foreach (DictionaryEntry entry in reader)
{
if (entry.Key.ToString().Equals(url.ToLower()))
return true;
}
}
}
}
return false;
}
Usage:
string url = "Pages/Page2.baml"; //<-- note the file extension
MessageBox.Show(IsRelativeUrl(url).ToString());
Related
So, i have a function that will load an image from disk async in an other thread ( big images will be loaded and I don't want the UI THread to be locked while loading).
Loading is done like this
public override void LoadFile()
{
using (var imageStream = new FileStream(_filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
Decoder = new TiffBitmapDecoder(imageStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
InitializeFile();
}
}
Then I want to use the Decoder on the main thread
public List<ThumbnailModel> LoadPages()
{
var result = new List<ThumbnailModel>();
foreach (var frame in Decoder.Frames) <--// this line throws exception
{
result.Add(new ThumbnailModel
{
Name = _metadataLoader.GetPageName((BitmapMetadata)frame.Metadata),
Bitmap = new WriteableBitmap(frame)
});
}
return result;
}
Now here is the problem, whenever I reach the line where I try to access the Decoder.Frames it throws exception (The calling thread cannot access this object because a different thread owns it.)
Is there a way I can use my Decoder in the main thread if not, the only possible solution is to load all the image information in the other thread?
Full code version :
// this is the task, that calls the imageFactory LoadFile method - NewThread
private async Task OpenFileAsync(string strFilePath)
{
var newFile = _imageFileFactory.LoadFile(strFilePath);
if (newFile != null)
{
_imagefile = newFile;
}
}
//image factory load file - NewThread
public IImageFile LoadFile(string filePath)
{
if (string.IsNullOrWhiteSpace(filePath))
{
return null;
}
var fileExtension = Path.GetExtension(filePath); // .tiff or .jpeg
var file = new ImageFileTiff(filePath, _metatadaFactory, _metadataVersioner);
file.LoadFile();
return file;
}
// ImageFileTiff LoadFile will create a decoder - NewThread
public override void LoadFile()
{
using (var imageStream = new FileStream(_filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
Decoder = new JpegBitmapDecoder(imageStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
InitializeFile();
}
}
After we have an IImageFile we call on MainThread(UIThread)
var pages = _imagefile.LoadPages();
Where LoadPages is the place where the app breaks. also called on UIThread
public List LoadPages()
{
var result = new List();
foreach (var frame in Decoder.Frames)
{
result.Add(new ThumbnailModel
{
Name = _metadataLoader.GetPageName((BitmapMetadata)frame.Metadata),
Bitmap = new WriteableBitmap(frame)
});
}
return result;
}
I thought you could simply return the decoder from the thread to be able to access it but your decoder is a TiffBitmapDecoder which inherits from DispatcherObject (https://learn.microsoft.com/en-gb/dotnet/api/system.windows.threading.dispatcherobject?view=netcore-3.1).
So you won't be able to access it from a different thread than the one where it was created msdn:"Only the thread that the Dispatcher was created on may access the DispatcherObject directly"
What you could do instead is use the decoder in it's thread and return the final result:
I couldn't build on your sample since there was to much missing for me to test it but I built a similar project to give an exemple:
public partial class MainWindow : Window
{
public MainWindow()
{
}
public TiffBitmapDecoder LoadFile()
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.InitialDirectory = "c:\\";
openFileDialog.Filter = "tiff files (*.tif)|*.tif|All files (*.*)|*.*";
openFileDialog.FilterIndex = 2;
openFileDialog.RestoreDirectory = true;
if (openFileDialog.ShowDialog() == true && !string.IsNullOrEmpty(openFileDialog.FileName))
{
//I didn't bother to check the file extension since it's just an exemple
using (var imageStream = openFileDialog.OpenFile())
{
return new TiffBitmapDecoder(imageStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
}
}
else
{
//User cancelled
return null;
}
}
public List<ThumbnailModel> LoadPages(TiffBitmapDecoder decoder)
{
//TiffBitmapDecoder" inherits from DispatcherObject/>
//https://learn.microsoft.com/en-gb/dotnet/api/system.windows.threading.dispatcherobject?view=netcore-3.1
var result = new List<ThumbnailModel>();
if (decoder != null)
{
try
{
foreach (var frame in decoder.Frames)
{
result.Add(new ThumbnailModel
{
//set the variables
});
}
}
catch(InvalidOperationException e)
{
MessageBox.Show(e.Message, "Error");
}
}
else
{
//Nothing to do
}
return result;
}
private async Task AsyncLoading()
{
this.thumbnailModels = await Task.Run<List<ThumbnailModel>>(() =>
{
var decoder = this.LoadFile();
return this.LoadPages(decoder);
});
}
private List<ThumbnailModel> thumbnailModels = null;
private async void AsyncLoadingButton_Click(object sender, RoutedEventArgs e)
{
await this.AsyncLoading();
}
}
public class ThumbnailModel
{
}
Content of MainWindow.xaml just in case:
<Grid>
<StackPanel Orientation="Vertical">
<Button x:Name="NoReturnButton" Margin="10" HorizontalAlignment="Center" Content="Call AsyncLoadingNoReturn" Click="AsyncLoadingButton_Click" />
</StackPanel>
</Grid>
I am testing MediaElement in WPF.
but frequently Directory.Delete function show error.
I don't know Why the error occurs.
MediaElement mediatest = new MediaElement();
mediatest.LoadedBehavior = MediaState.Manual;
root.Children.Add(mediatest);
mediatest.BeginInit();
mediatest.Source = null;
mediatest.Source = new Uri(MediaSrc);
mediatest.EndInit();.
mediatest.Play();
stop()
mediatest.Stop();
mediatest.Close();
mediatest.Source = null;
mediatest = null;
root.Children.Clear();
System.IO.Directory.Delete(System.IO.Path.Combine(Environment.CurrentDirectory, #"sound"), true);
Try to use instead of Directory.Delete the following method:
public static void DeleteDirectory(string target_dir)
{
string[] files = Directory.GetFiles(target_dir);
string[] dirs = Directory.GetDirectories(target_dir);
foreach (string file in files)
{
File.SetAttributes(file, FileAttributes.Normal);
File.Delete(file);
}
foreach (string dir in dirs)
{
DeleteDirectory(dir);
}
Directory.Delete(target_dir, false);
}
I tried it, but the same issue appear. and I am trying to check it.
mediatest.Stop();
mediatest.Close();
mediatest.Source = null;
mediatest = null;
root.Children.Clear();
GC.Collect();
but the same issue appear again.
and then I changed source following
GC.Collect();
Thread.Sleep(500);
now I didn't see an error so far.
I have hundreds of different random URLs coming in, all documents in libs, without any other parameters from different farms and different site collections and sites, goal is to download a file as a binary array from SharePoint.
So e.g. incoming url = http://a.b.c.d.e/f.g/h.i/j/k/l/m.docx .
So how to get the (a) correct site collection root url (b) site root url (c) library root url from this? The only way I now think of is slowly stripping off each part of the url until e.g. .Rootfolder no longer gives an exception... or the other way around slowly adding bits by the first part of the url until rootfolder nog longers gives an exception then query for subwebs etc..
The point is that ClientContext constructor accepts the url of web/site only.
But if the url will be specified in the following format:
http://site/web/documents/file.docx
then the exception System.Net.WebException will occur.
The following example demonstrates how to resolve ClientContext from request Url:
public static class ClientContextUtilities
{
/// <summary>
/// Resolve client context
/// </summary>
/// <param name="requestUri"></param>
/// <param name="context"></param>
/// <param name="credentials"></param>
/// <returns></returns>
public static bool TryResolveClientContext(Uri requestUri, out ClientContext context, ICredentials credentials)
{
context = null;
var baseUrl = requestUri.GetLeftPart(UriPartial.Authority);
for (int i = requestUri.Segments.Length; i >= 0; i--)
{
var path = string.Join(string.Empty, requestUri.Segments.Take(i));
string url = string.Format("{0}{1}", baseUrl, path);
try
{
context = new ClientContext(url);
if (credentials != null)
context.Credentials = credentials;
context.ExecuteQuery();
return true;
}
catch (Exception ex) {}
}
return false;
}
}
Usage
ClientContext context;
if (ClientContextUtilities.TryResolveClientContext(requestUri, out context, null))
{
using (context)
{
var baseUrl = requestUri.GetLeftPart(UriPartial.Authority);
var fileServerRelativeUrl = requestUri.ToString().Replace(baseUrl, string.Empty);
var file = context.Web.GetFileByServerRelativeUrl(fileServerRelativeUrl);
context.Load(file);
context.Load(context.Web);
context.Load(context.Site);
context.ExecuteQuery();
}
}
Since your goal is to download a file, there is pretty straightforward way to accomplish it without parsing url parts.
For example, using WebClient.DownloadFile Method:
private static void DownloadFile(Uri fileUri, ICredentials credentials, string localFileName)
{
using(var client = new WebClient())
{
client.Credentials = credentials;
client.DownloadFile(fileUri, localFileName);
}
}
I have made a working method but it seems elaborate, so any suggestions for improvement are welcome just to "download file if one of the specific columns has value "yes":
public void getDocument(Document doc)
{
// get the filename
Uri uri = new Uri(doc.uri);
doc.filename = "";
doc.filename = System.IO.Path.GetFileName(uri.LocalPath);
//string fullPathWithoutFileName = docUri.Replace(filename, "");
// would also include ?a&b so:
string[] splitDocUri = doc.uri.Split('/');
string fullPathWithoutFileName = "";
for (int i = 0; i < splitDocUri.Length -1; i++)
{
fullPathWithoutFileName += (splitDocUri[i] + '/');
}
// get via "_api/contextinfo" the context info
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(fullPathWithoutFileName + "_api/contextinfo");
req.Method = "POST";
req.Accept = "application/json; odata=verbose";
req.Credentials = new NetworkCredential(doc.username, doc.password, doc.domain);
req.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED","f");
req.ContentLength = 0;
BypassCertificateError();
HttpWebResponse rp = (HttpWebResponse)req.GetResponse();
Stream postStream = rp.GetResponseStream();
StreamReader postReader = new StreamReader(postStream);
string results = postReader.ReadToEnd();
// Now parse out some values needs system.web.extensions
JavaScriptSerializer jss = new JavaScriptSerializer();
var d = jss.Deserialize<dynamic>(results);
string formDigestValue = d["d"]["GetContextWebInformation"]["FormDigestValue"];
// the full url to the website e.g. "http://server:7777/level1/level 2"
string webFullUrl = d["d"]["GetContextWebInformation"]["WebFullUrl"];
// the full url to the site collection e.g. "http://server:7777"
string siteFullUrl = d["d"]["GetContextWebInformation"]["SiteFullUrl"];
// now we can create a context
ClientContext ctx = new ClientContext(webFullUrl);
ctx.ExecutingWebRequest +=
new EventHandler<WebRequestEventArgs>(ctx_MixedAuthRequest);
BypassCertificateError();
ctx.AuthenticationMode = ClientAuthenticationMode.Default;
ctx.Credentials = new NetworkCredential(doc.username, doc.password, doc.domain);
// Get the List
Microsoft.SharePoint.Client.File file = ctx.Web.GetFileByServerRelativeUrl(uri.AbsolutePath);
List list = file.ListItemAllFields.ParentList;
ctx.Load(list);
ctx.ExecuteQuery();
// execute a CAML query against it
CamlQuery camlQuery = new CamlQuery();
camlQuery.ViewXml =
"<View><Query><Where><Eq><FieldRef Name='FileLeafRef'/>" +
"<Value Type='Text'>" + doc.filename + "</Value></Eq></Where>" +
"<RowLimit>1</RowLimit></Query></View>";
ListItemCollection listItems = list.GetItems(camlQuery);
ctx.Load(listItems);
try {
ctx.ExecuteQuery();
}
catch
{
// e.g. : no access or the listname as incorrectly deduced
throw;
}
// and now retrieve the items needed
if (listItems.Count == 1)
{
ListItem item = listItems[0];
// some more checking from testColumn to decide if to download yes/no
string testColumn;
if (item.IsPropertyAvailable("testColumn")) {
testColumn = (string)item["testColumn"];
}
FileInformation fileInformation =
Microsoft.SharePoint.Client.File.OpenBinaryDirect(ctx,
(string)item["FileRef"]);
doc.bytes = ReadFully(fileInformation.Stream);
}
else
{
doc.errormessage = "Error: No document found";
}
}
In the 9.3 code you could just do a MapLayer.Layer to get the FeatureLayer.
But in 10.1.1 they changed FeatureLayer to FeatureSource AND removed the Layer property from MapLayer.
Here's the old code someone else wrote that I'm upgrading:
static public MapLayer FindMapLayer(string sLayerName, Map theMap)
{
MapLayer lyr = null;
try
{
lyr = theMap.MapLayers[sLayerName];
}
catch { }
return lyr;
}
static public FeatureLayer FindFeatureLayer(string sLayerName, Map theMap)
{
FeatureLayer featLyr = null;
MapLayer lyr = FindMapLayer(sLayerName, theMap);
if (lyr != null)
{
featLyr = lyr.Layer;
}
return featLyr;
}
I figured it out. You have to look in the mobilecache.FeatureSources collection. The Name will match the same name you named the LAYER in your MXD (the exact string you see in the table of contents) that you published as a service in ArcGIS Server.
public static FeatureSource FindFeatureLayer(string featureSourceName, Map theMap)
{
//TODO: this may not work if the feature source name doesn't match the map layer name!
FeatureSource featSource = null;
//10.1.1
//Just grab the first map layer in order to get at the mobile cache and its
// collection of feature sources.
MobileCacheMapLayer cacheMapLayer = GetMobileCacheLayer(theMap);
if (cacheMapLayer != null)
{
featSource = cacheMapLayer.MobileCache.FeatureSources[featureSourceName];
}
return featSource;
}
public static MobileCacheMapLayer GetMobileCacheLayer(Map theMap)
{
foreach (var layer in theMap.MapLayers)
{
if(layer is MobileCacheMapLayer)
return (MobileCacheMapLayer)layer;
}
return null;
}
I have this application where I use windowsForm and UserControl to draw some diagrams. After I am done I want to save them or I want to open an existing file that I created before and keep working on the diagram. So, I want to use the save and open dialog File to save or open my diagrams.
EDIT:
this is what i have :
//save the object to the file
public bool ObjectToFile(Object model, string FileName)
{
try
{
System.IO.MemoryStream _MemoryStream = new System.IO.MemoryStream();
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter _BinaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
_BinaryFormatter.Serialize(_MemoryStream, model);
byte[] _ByteArray = _MemoryStream.ToArray();
System.IO.FileStream _FileStream = new System.IO.FileStream(FileName, System.IO.FileMode.Create, System.IO.FileAccess.Write);
_FileStream.Write(_ByteArray.ToArray(), 0, _ByteArray.Length);
_FileStream.Close();
_MemoryStream.Close();
_MemoryStream.Dispose();
_MemoryStream = null;
_ByteArray = null;
return true;
}
catch (Exception _Exception)
{
Console.WriteLine("Exception caught in process: {0}", _Exception.ToString());
}
return false;
}
//load the object from the file
public Object FileToObject(string FileName)
{
try
{
System.IO.FileStream _FileStream = new System.IO.FileStream(FileName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
System.IO.BinaryReader _BinaryReader = new System.IO.BinaryReader(_FileStream);
long _TotalBytes = new System.IO.FileInfo(FileName).Length;
byte[] _ByteArray = _BinaryReader.ReadBytes((Int32)_TotalBytes);
_FileStream.Close();
_FileStream.Dispose();
_FileStream = null;
_BinaryReader.Close();
System.IO.MemoryStream _MemoryStream = new System.IO.MemoryStream(_ByteArray);
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter _BinaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
_MemoryStream.Position = 0;
return _BinaryFormatter.Deserialize(_MemoryStream);
}
catch (Exception _Exception)
{
Console.WriteLine("Exception caught in process: {0}", _Exception.ToString());
}
return null;
}
and now I want to do this but it's not working
public void save()
{
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.Filter = "txt files (*.txt)|*.txt";
saveFileDialog1.FilterIndex = 2;
saveFileDialog1.RestoreDirectory = true;
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
if (saveFileDialog1.OpenFile() != null)
{
ObjectToFile(model, saveFileDialog1.FileName);
}
}
}
but if I try without the fileDialog and i just use
ObjectToFile(model, "d:\\objects.txt");
this works. And I want to save it where I want and with my own name.
Check out the SaveFileDialog and OpenFileDialog classes. They are pretty similar, and can be used like this:
using(SaveFileDialog sfd = new SaveFileDialog()) {
sfd.Filter = "Text Files|*.txt|All Files|*.*";
if(sfd.ShowDialog() != DialogResult.OK) {
return;
}
ObjectToFile(sfd.FileName);
}
The mechanics of actually saving your file are, obviously, outside the scope of this answer.
Edit: I've updated my answer to reflect the new information in your post.