0

I have done all of the things necessary to gaining access to the files located on the SD card of my IOT device (DragonBoard 410c).

I have all of the FileTypeAssociations

    <Capability Name="internetClient" />
    <Capability Name="privateNetworkClientServer" />
    <Capability Name="internetClientServer" />
    <uap:Capability Name="userAccountInformation" />
    <uap:Capability Name="removableStorage" />
    <uap:Capability Name="enterpriseAuthentication" />

I CAN see and iterate over the files on the SD card

StorageFolder removablelDevices = Windows.Storage.KnownFolders.RemovableDevices;
StorageFolder sdCard = (await removablelDevices.GetFoldersAsync()).FirstOrDefault();
var files = await nm.GetFilesAsync();

foreach (var file in files)
{
    DebugText(file.Path);
    //E:\Photo1.jpg
    //E:\Photo2.jpg
}

I am setting the ImageSource of the ImageBrush of the Background to these pictures in a slideshow.

private ImageSource _CurrentPicture;
public ImageSource CurrentPicture { get { return _CurrentPicture; } set { Set(ref _CurrentPicture, value); } }

<ImageBrush  Stretch="UniformToFill" ImageSource="{x:Bind ViewModel.CurrentPicture, Mode=OneWay}"/>

The pictures do not show up (E:\Photo1.jpg etc)

I AM able to iterate over fileshares on a local server during development mode, so my pictures do show on my Background in that scenario.


I am updating the background with a DispatchTimer.
Now that file access is async, I am running into async hell.

public void TimerSetup()
{
    SlideShowTimer = new DispatcherTimer();
    SlideShowTimer.Tick += SlideShowTimer_Tick;
    SlideShowTimer.Interval = new TimeSpan(0, 0, SlideShowChangeIntervalSeconds);
    SlideShowTimer.Start();

}
void SlideShowTimer_Tick(object sender, object e)
{
    ChangeBackground();
}
public async Task ChangeBackground()
{
    var nextIndex = RandomGenerator.Next(0, SlideShowFiles.Length);
    var fileName = SlideShowFiles[nextIndex];
    var file = await StorageFile.GetFileFromPathAsync(fileName);
    var stream = await file.OpenAsync(FileAccessMode.Read);
    await CurPicImage.SetSourceAsync(stream);
    await Task.CompletedTask;
}
Terrence
  • 313
  • 2
  • 12

1 Answers1

2

The ImageSource property on ImageBrush doesn't automatically convert file paths to ImageSource object. You will have to do the conversion in your code:

var file = await StorageFile.GetFileFromPathAsync(@"E:\Photo1.jpg");
var stream = await file.OpenAsync(FileAccessMode.Read);
var bitmapImage = new Windows.UI.Xaml.Media.Imaging.BitmapImage();
imageBrush.ImageSource = bitmapImage;
await bitmapImage.SetSourceAsync(stream);

The above is the simple (quick & dirty) way to set an imagebrush from file path in code. The more elegant way will be to implement an IValueConverter to be used in your data binding. Since you want the data binding to be async and not block the UI thread there is a little bit more coding required. The details of how to implement an async IValueConverter can be found in this excellent answer: Async Implementation of IValueConverter

Stefan Wick MSFT
  • 13,600
  • 1
  • 32
  • 51
  • Stefan, thank you so much for your solution. I would love it if you could show me an example of the IValueConverter way of doing it. In the long run, I want to be coding with best practices. – Terrence Feb 03 '19 at 04:17
  • I have edited my answer with a pointer to how to implement an async IValueConverter, which had been answered in the past on a different question. – Stefan Wick MSFT Feb 03 '19 at 04:24
  • Stefan, your solution worked. Thank you. I have edited my post to show new code and you see now I am in async hell because my DispatchTimer is not async. I guess I will have to follow the async IValueConverter route. – Terrence Feb 03 '19 at 15:36
  • What exactly is the problem you are facing with the DispatcherTimer? I can't tell from the updated question. Might be worth posting a separate question, but it should be pretty straight forward. – Stefan Wick MSFT Feb 03 '19 at 15:42
  • In order to call ChangeBackground(), I have to turn the SlideShowTimer_Tick method into an async method, when I do that the event handler code SlideShowTimer.Tick += SlideShowTimer_Tick; blows up. – Terrence Feb 03 '19 at 16:40
  • I also posted another related question about using a Uri instead of a stream for this issue [Network Uri vs Local Uri](https://stackoverflow.com/questions/54505254/) – Terrence Feb 03 '19 at 16:58
  • To fix your DispatcherTimer bug just change the function to "public async void ChangeBackground()" and remove the "await Task.CompletedTask;" line. – Stefan Wick MSFT Feb 03 '19 at 17:18
  • Stefan, when I make those changes, the ticker ticks, and the bitmapimage source gets set, but the image does not show on the screen. – Terrence Feb 03 '19 at 18:32
  • It works for me. As it worked for you for one file there is no reason it wouldn't work in a loop or on a timer. I think you need to debug your code a little more. If that doesn't help I would suggest you open a new question about the DispatcherTimer problem you are facing and include a complete repro. In your latest update, for example it is not clear what is 'CurPicImage'. It's not in your XAML, so we can only speculate. – Stefan Wick MSFT Feb 03 '19 at 21:44
  • You are the man. I was switching back and for between my original ImageSource and a BitmapImage. Now they are aligned and it works. Thank you very much for sticking with me on this. – Terrence Feb 03 '19 at 22:15
  • Glad it's working now - have fun with your IoT project! Please mark as answer so we get this off the list. Cheers! – Stefan Wick MSFT Feb 03 '19 at 22:26