1

I'm using a XamDataTree and I need the node icons to have different images for every type of node. I tried asking this on Infragistics, but we don't understand each other :(

Also the problem really has nothing to do with their control anymore, it's about how to get an image stored in the model to show. Yes this is against the principles of MVVM, but this is the only workable way of showing the images.

Note: I have a workaround, use a Label to specify the node contents and put a horizontal stackpanel in it that has the image and node text in it. But this is crappy, I want the XamDataGrid object to show the image.

There are 28 different images to show here, some of which are created dynamically. So I don't want to make a ton of different templates that load the images by file path and then use different templates.

The XamDataTree, I also tried specifying the binding with Element name or !. I'm trying to load the image directly from the model or through a DataTemplate:

<ig:XamDataTree
    ScrollViewer.CanContentScroll="True"
    ItemsSource="{Binding Model}"
    HorizontalAlignment="Stretch"
    VerticalAlignment="Stretch"
    NodeLineVisibility="Visible"
    >
    <ig:XamDataTree.Resources>
        <DataTemplate x:Key="nodeImage" >
            <Image Source="{Binding Path=NodeImage}" />
        </DataTemplate>
    </ig:XamDataTree.Resources>
    <ig:XamDataTree.GlobalNodeLayouts>
        <ig:NodeLayout
            ExpandedIconTemplate="{StaticResource nodeImage}"
            CollapsedIconTemplate="{Binding NodeImage}"
            Key="Children"
            DisplayMemberPath="Name"
            TargetTypeName="Model"
            >
        </ig:NodeLayout>
    </ig:XamDataTree.GlobalNodeLayouts>
</ig:XamDataTree>

The model that I use, the image source value is set elsewhere:

public class Model
{
    /// <summary>
    /// Image representing the type of node this is.
    /// </summary>
    public ImageSource NodeImage
    {
        get
        {
            return this.nodeImage;
        }
        set
        {
            this.nodeImage = value;
            this.OnPropertyChanged("NodeImage");
        }
    }

    /// <summary>
    /// Controls will bind their attributes to this event handler.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// Fire an event alerting listners a property changed.
    /// </summary>
    /// <param name="name">Name of the property that changed.</param>
    public void OnPropertyChanged(string name)
    {
        // Check whether a control is listening.
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }
}

Edit: I tried loading the images directly from files into a BitmapImage, then storing them in the model, din't work. When using higher debugging level messaging it posts messages in the output that the databinding cannot find the corrosponding property. So the problem is most likely in my data binding.

Community
  • 1
  • 1
MrFox
  • 4,852
  • 7
  • 45
  • 81

2 Answers2

3

Another solution would be to use a converter and the type Stream for your property NodeImage.

Converter:

public class StreamToImageConverter : IValueConverter {
  public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
        var imageStream = value as System.IO.Stream;
        if (imageStream != null)) {
            System.Windows.Media.Imaging.BitmapImage image = new System.Windows.Media.Imaging.BitmapImage();
            image.SetSource(imageStream );
            return image;
        }
        else {
           return null;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
        throw new NotImplementedException();
    }
}

Property:

private Stream _imageStream;
public Stream NodeImage
{
    get
    {
        return _imageStream;
    }
    set
    {
        _imageStream= value;
        this.OnPropertyChanged("NodeImage");
    }
}

XAML:

<Grid>
   <Grid.Resources>
     <local:StreamToImageConverter x:Name="imageConverter"/>
   </Grid.Resources>
   <Image Source="{Binding Path=NodeImage, Converter={StaticResource imageConverter}" />
 </Grid>
Jehof
  • 34,674
  • 10
  • 123
  • 155
1

Change your property NodeImage to type string and return the path of the Image. The rest is done by the Image and the converter classes that convert your path to a ImageSource.

private string _imagePath;
public string NodeImage
{
    get
    {
        return _imagePath;
    }
    set
    {
        _imagePath = value;
        this.OnPropertyChanged("NodeImage");
    }
}
Jehof
  • 34,674
  • 10
  • 123
  • 155
  • 1
    Some of the images are created dynamically. – MrFox Mar 15 '13 at 11:00
  • What do you mean by dynamically? Do you store them in the FileSystem? May be you should update your answer how the images are created – Jehof Mar 15 '13 at 11:01
  • I combine different images to create new ones to show. This could be done beforehand. But won't this cause every image to be loaded from disk every time? Instead of loading the image from disk once, construct another image and use them both in many places. – MrFox Mar 15 '13 at 11:04
  • @MrFox Try it, i think not that this is a real performance issue. – Jehof Mar 15 '13 at 11:05
  • 1
    Instead of a string return a URI. new Uri("/ApplicationCatalogModule;component/Images/Applications-icon.png",UriKind.Relative) for example. – TYY Mar 15 '13 at 11:16
  • @MrFox I´ve provided another answer – Jehof Mar 15 '13 at 11:17
  • I tried loading the images from file into a BitmapImage and then showing it, which does not work. I'm probably doing something work with my XAML bindings. – MrFox Mar 21 '13 at 15:38