0

I just want to convert file size in string format like "1 MB" or "2.5 GB", I referred converter from Q.42 library I think, I may be having mistake in my XAML code, please help me to figure out this.

MainPage.XAML

<Page.Resources>
    <local:ByteToStringConverter x:Key="BytesToString" />
</Page.Resources>
<Grid>
    <TextBlock Text="{Binding Path=Size, Converter={StaticResource BytesToString}}"/>
</Grid>

MainPage.XAML.cs

public sealed partial class MainPage : Page
{

    public MainPage()
    {
        this.InitializeComponent();
    }

    protected async override void OnNavigatedTo(NavigationEventArgs e)
    {
        StorageFile f = await KnownFolders.MusicLibrary.GetFileAsync("video.mp4");
        BasicProperties bs = await f.GetBasicPropertiesAsync();
        MyClass obj = new MyClass();
        obj.Size = bs.Size;
    }
}

public class MyClass : INotifyPropertyChanged
{
    private ulong _Size;

    public ulong Size
    {
        get { return _Size; }
        set { _Size = value; OnPropertyChanged("Size");}
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

ByteToStringConverter.cs

public class ByteToStringConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        string size = "0 KB";

        if (value != null)
        {

            double byteCount = 0;

            byteCount = System.Convert.ToDouble(value);

            if (byteCount >= 1073741824)
                size = String.Format("{0:##.##}", byteCount / 1073741824) + " GB";
            else if (byteCount >= 1048576)
                size = String.Format("{0:##.##}", byteCount / 1048576) + " MB";
            else if (byteCount >= 1024)
                size = String.Format("{0:##.##}", byteCount / 1024) + " KB";
            else if (byteCount > 0 && byteCount < 1024)
                size = "1 KB";    //Bytes are unimportant ;)            
        }

        return size;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}
Farhan Ghumra
  • 15,180
  • 6
  • 50
  • 115

1 Answers1

0

[Edit: Updated to reflect new code]

First, tmplement the INotifyPropertyChanged interface in MyClass and fire the PropertyChanged event when Size is changed. That will ensure the binding is updated.

Second, set the data binding of the page to an instance of MyClass, such as

<Page.DataContext> 
    <local:MyClass/> 
</Page.DataContext>

which you have indicated that you have done.

Third, instead of creating a new instance of MyClass in OnNavigatedTo, set the property on the instance the MainPage has bound to. For example:

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    StorageFile f = await KnownFolders.MusicLibrary.GetFileAsync("video.mp4");
    BasicProperties bs = await f.GetBasicPropertiesAsync();

    // Do not create a new instance       
    ((MyClass) DataContext).Size = bs.Size;
}

Why? Binding in WPF is done to specific object instances. For example, if control A binds to object X and a property of object X changes, control A will be updated. If a control A binds to an object X but the value of another object Y changes, control A will not be notified.

Creating a new object in OnNavigatedTo created an object Y. Instead, you wanted to set the Size property on object X instead.

To debug this:

  • Try it without the converter first to ensure the value is updated then add the converter. This will separate any converter issues from binding issues.
  • Put a breakpoint in the setter for Size. If it is hit, the issue is with the binding. If not, the issue is that Size is not being set.

Very minor side point: Use a ulong instead of double in Convert. ulongs give 64 bits of precision whereas doubles only give 53 bits of precision. You may never see something that big in bytes but it also keeps it consistent with the property type in MainPage.

akton
  • 14,148
  • 3
  • 43
  • 47
  • Still data is not getting bind with textblock, i tried with removing converter – Farhan Ghumra Sep 26 '12 at 12:06
  • What is the `DataContext` set to? Try setting it to the page itself. – akton Sep 26 '12 at 12:11
  • Whose `DataContext` ? I tried in MainPage.xaml.cs with `this.DataContext = this`, but not working. – Farhan Ghumra Sep 26 '12 at 12:41
  • I read the updated code. Two changes. First: Set the binding to an instance of `MyClass`. not the page (possibly my mistake). Second: Store the MyClass object in a class field. Otherwise, it may go out of scope and be garbage collected. – akton Sep 26 '12 at 12:49
  • Put a breakpoint on the setter in the Size property and see if it is called. That will tell you whether the issue is before or after that. – akton Sep 26 '12 at 12:50
  • I am not getting you. I think binding should be set with property name i.e. `Size` not the instance of class (here `MyClass`). If I am wrong then please post the whole code. I put this in MainPage.xaml ` ` I put breakpoint on setter, value is set but not being displayed. – Farhan Ghumra Sep 26 '12 at 12:59
  • It worked :) Can you please explain why creating new instance doesn't show the value ? – Farhan Ghumra Sep 26 '12 at 13:11
  • Added an explanation to the answer. – akton Sep 26 '12 at 13:16