当引用不在ItemsSource中时,WPF绑定到ComboBox SelectedItem

时间:2022-07-10 17:01:32

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.

我将PrintQueue的PageMediaSize集合绑定到ComboBox的ItemSource(这很好)。然后我将ComboBox的SelectedItem绑定到PrintQueue的DefaultPrintTicket.PageMediaSize。虽然这会将所选值设置为DefaultPrintTicket.PageMediaSize就好了,它不会将最初选择的ComboBox值设置为DefaultPrintTicket.PageMediaSize的初始值这是因为DefaultPrintTicket.PageMediaSize引用与之中的任何引用都不匹配采集。但是我不希望它通过引用来比较对象,而是通过值来比较,但是PageMediaSize不会覆盖Equals(我无法控制它)。我真正想做的是设置一个IComparable供ComboBox使用,但我没有看到任何方法。我试图使用转换器,但我需要的不仅仅是值,我无法弄清楚如何将集合传递给ConverterProperty。关于如何处理这个问题的任何想法。

Here's my xaml

这是我的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

以及获取PageMediaSize集合的转换器的代码

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.

我尝试将DefaultPrintTicket.PageMediaSize设置为InitializeComponent之前的集合中的相应引用,但这不起作用。当我从ComboBox中选择某些内容时,它肯定会设置该值,但它似乎没有其他方式。

2 个解决方案

#1


2  

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.

是否可以为PageMediaSize创建一个包装类并覆盖此包装类中的Equals(object)方法?然后,您可以将此包装类的实例添加到集合中,以便不再通过引用对它们进行比较。当然,您需要一些代码来包装和解包您的PageMediaSize实例,但这是我能想象到的最佳方式。

#2


1  

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

根据juharr的回答,您可以使用转换器来包装和展开对象。

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.

在xaml中,在ItemSource和Selected Item上使用转换器。

<ComboBox                                                               
    ItemsSource="{Binding MySource, Converter={StaticResource toTypeEqualityWrapper}}" 
    SelectedItem="{Binding MySelectedItem, Converter={StaticResource toTypeEqualityWrapper}}"                                                             
    DisplayMemberPath="Value.DisplayName" />

#1


2  

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.

是否可以为PageMediaSize创建一个包装类并覆盖此包装类中的Equals(object)方法?然后,您可以将此包装类的实例添加到集合中,以便不再通过引用对它们进行比较。当然,您需要一些代码来包装和解包您的PageMediaSize实例,但这是我能想象到的最佳方式。

#2


1  

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

根据juharr的回答,您可以使用转换器来包装和展开对象。

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.

在xaml中,在ItemSource和Selected Item上使用转换器。

<ComboBox                                                               
    ItemsSource="{Binding MySource, Converter={StaticResource toTypeEqualityWrapper}}" 
    SelectedItem="{Binding MySelectedItem, Converter={StaticResource toTypeEqualityWrapper}}"                                                             
    DisplayMemberPath="Value.DisplayName" />