Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF binding to ComboBox SelectedItem when reference not in ItemsSource

I'm binding the PageMediaSize collection of a PrintQueue to the ItemSource of a ComboBox (This works fine). Then I'm binding the SelectedItem of the ComboBox to the DefaultPrintTicket.PageMediaSize of the PrintQueue. While this will set the selected value to the DefaultPrintTicket.PageMediaSize just fine it does not set the initially selected value of the ComboBox to the initial value of DefaultPrintTicket.PageMediaSize This is because the DefaultPrintTicket.PageMediaSize reference does not match any of the references in the collection. However I don't want it to compare the objects by reference, but instead by value, but PageMediaSize does not override Equals (and I have no control over it). What I'd really like to do is setup a IComparable for the ComboBox to use, but I don't see any way to do that. I've tried to use a Converter, but I would need more than the value and I couldn't figured out how to pass the collection to the ConverterProperty. Any ideas on how to handle this problem.

Here's my xaml

<ComboBox x:Name="PaperSizeComboBox" 
          ItemsSource="{Binding ElementName=PrintersComboBox, Path=SelectedItem, 
                        Converter={StaticResource printQueueToPageSizesConverter}}"
          SelectedItem="{Binding ElementName=PrintersComboBox, 
                         Path=SelectedItem.DefaultPrintTicket.PageMediaSize}"
          DisplayMemberPath="PageMediaSizeName"
          Height="22"
          Margin="120,76,15,0"
          VerticalAlignment="Top"/>

And the code for the converter that gets the PageMediaSize collection

public class PrintQueueToPageSizesConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter,
                          System.Globalization.CultureInfo culture)
    {
        return value == null ? null :
            ((PrintQueue)value).GetPrintCapabilities().PageMediaSizeCapability;
    }

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

Edit

I tried setting the DefaultPrintTicket.PageMediaSize to the corresponding reference in the collection before InitializeComponent, but that did not work. It's definately setting the value when I select something from the ComboBox, but it doesn't seem to go the other way.

like image 527
juharr Avatar asked Jun 03 '10 19:06

juharr


2 Answers

Would it be possible to create a wrapper class for PageMediaSize and override the Equals(object) method in this wrapper class? You could then add instance of this wrapper class to your collection, so that they are no longer compared by reference. Of course, you will need some code for wrapping and unwrapping your PageMediaSize instances, but that's the best way I can imagine.

like image 85
gehho Avatar answered Oct 16 '22 01:10

gehho


Further to juharr's answer, you could use a converter to wrap and unwrap the object.

using System;
using System.Collections;
using System.Globalization;
using System.Linq;
using System.Windows.Data;

namespace MyNameSpace
{
    public class ToTypeEqualityWrapper : IValueConverter
    {
        public class TypeEqualityWrapper
        {
            public object Value { get; set; }

            public TypeEqualityWrapper(object value)
            {
                Value = value;
            }

            public override bool Equals(object obj)
            {
                var otherWrapper = obj as TypeEqualityWrapper;
                if (otherWrapper == null)
                    return false;

                var result = Value.GetType().FullName == otherWrapper.Value.GetType().FullName;
                return result;
            }
        }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var list = value as IList;
            if (list != null)
            {
                return (from object item in list select new TypeEqualityWrapper(item)).Cast<object>().ToList();
            }

            return new TypeEqualityWrapper(value);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var wrapper = value as TypeEqualityWrapper;
            if(wrapper != null)
                return wrapper.Value;

            return value;
        }
    }
}

Then declare your converter

<ns:ToTypeEqualityWrapper x:Key="toTypeEqualityWrapper" />    

In the xaml, use the converter on both ItemSource and Selected Item.

<ComboBox                                                               
    ItemsSource="{Binding MySource, Converter={StaticResource toTypeEqualityWrapper}}" 
    SelectedItem="{Binding MySelectedItem, Converter={StaticResource toTypeEqualityWrapper}}"                                                             
    DisplayMemberPath="Value.DisplayName" />
like image 22
jv_ Avatar answered Oct 16 '22 01:10

jv_