All ComboBoxes in a ListBox change when any 1 of t

2019-05-06 15:46发布

问题:

I have a ListBox on a form that is bound to an ObservableCollection of a custom type. Within each item there is a ComboBox bound to an enumeration type. When the window loads, all ComboBoxes are defaulted to a certain value. When I change the SelectedItem for any one (from the UI, not from code), all other ComboBoxes change to the same SelectedItem.

I'm not sure what I've done wrong, here is my current XAML that is handling this.

<Window.Resources>
    <ObjectDataProvider x:Key="SyncOperationValues"
                        MethodName="GetNames"
                        ObjectType="{x:Type sys:Enum}">
        <ObjectDataProvider.MethodParameters>
            <x:Type TypeName="local:SyncOperationEnum" />
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
...
    <DataTemplate x:Key="SyncListTemplate">
        <Grid Grid.Column="1" Grid.RowSpan="2" Margin="0,0,20,0" x:Name="olDetails"
            DataContext="{Binding Path=OlContact}">
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
            <RowDefinition />
            </Grid.RowDefinitions>
...
            <ComboBox x:Name="SyncOp" 
                Width="120" Height="19"
                Margin="4,0,10,0" 
                IsSynchronizedWithCurrentItem="True" 
                ItemsSource="{Binding Source={StaticResource SyncOperationValues}}"
                             SelectedItem="{Binding Operation}"
                             VerticalAlignment="Center" />

...

and the ListBox:

 <ListBox x:Name="SyncList"
     ScrollViewer.HorizontalScrollBarVisibility="Hidden"
     ItemContainerStyle="{StaticResource StretchedContainerStyle}"
     ItemTemplate="{StaticResource SyncListTemplate}">
 ListBox>

I have tried some different options, like binding to a CollectionView; however nothing seems to work. Can anyone point me to my mistake?

Thanks!

回答1:

I had a situation similar to this and setting the IsSynchronizedWithCurrentItem property on the ComboBox to "False" fixed it. The way I understand it, setting the value to "True" means the ComboBox value will be synchronized value of the current item for the ListBox. Basically, all the ComboBoxes are bound to that same value. It sounds like that is what you are experiencing. Try:

IsSynchronizedWithCurrentItem="False"


回答2:

I have finally found a solution. I ended up writing a ValueConverter for the enumeration type. I'd been under the impression that this was not necessary, but for some reason it is, at least if the ComboBox is within another list (ListBox in my case) of some sort.

I did need to set the IsSynchronizedWithCurrentItem property to false as John M suggested, so thanks to John for that! Here is the converter code in case anyone else needs to do something like this.

[ValueConversion( typeof( SyncOperationEnum ), typeof( String ) )]
public class SyncOperationConverter : IValueConverter {
    #region IValueConverter Members

    public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
        if( value != null && value.GetType() == typeof( SyncOperationEnum ) )
            return Enum.GetName( typeof( SyncOperationEnum ), value );

        return null;
    }

    public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
        if( value != null && targetType == typeof( SyncOperationEnum ) )
            foreach( object enumValue in Enum.GetValues( targetType ) )
                if( value.Equals( Enum.GetName( targetType, enumValue ) ) )
                    return enumValue;

        return null;
    }

    #endregion

And my XAML now looks like this:

<Window.Resources>
    <local:SyncOperationConverter x:Key="SyncConverter" />

    <ObjectDataProvider x:Key="SyncOperationValues"
                    MethodName="GetNames"
                    ObjectType="{x:Type sys:Enum}">
        <ObjectDataProvider.MethodParameters>
            <x:Type TypeName="local:SyncOperationEnum" />
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
...
<DataTemplate x:Key="SyncListTemplate">
    <Grid Grid.Column="1" Grid.RowSpan="2" Margin="0,0,20,0" x:Name="olDetails"
        DataContext="{Binding Path=OlContact}">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
        <RowDefinition />
        </Grid.RowDefinitions>
...
        <ComboBox x:Name="SyncOp" 
            Width="120" Height="19"
            Margin="4,0,10,0" 
            IsSynchronizedWithCurrentItem="False" 
            ItemsSource="{Binding Source={StaticResource SyncOperationValues}}"
            SelectedValue="{Binding Path=Operation,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,Converter={StaticResource SyncConverter}}"
            VerticalAlignment="Center" />


回答3:

It looks like your "Operation" property should be a Static property. Since it bind to every ComboBox when you change it, So everything else is right in your XAML just make the property like bellow

    static SyncOperationEnum _operation;

    public static SyncOperationEnum Operation
    {
        get { return _operation; }
        set { _operation = value;}
    }