Можно ли связать WPF Combobox.SelectedValue с несколькими ObjectDataProviders?

StackOverflow https://stackoverflow.com/questions/848946

Вопрос

Попытка определить, можно ли привязать SelectedValue ComboBox к входным данным нескольких ObjectDataProviders с помощью привязок XAMAL.

Я посмотрел MultiBinding, но, похоже, он группирует несколько элементов управления вместе, а это не совсем то, что я ищу сейчас.

Я бы хотел, чтобы ComboBox (местоположения) менял TextBlock (отклонение), что он делает, И вызывал ObjectDataProvider (CommentProvider) для обновления TextBox (locationComments).

В коде программной части это довольно просто, но я бы предпочел не идти по этому пути в качестве учебного опыта.

КОД КСАМАЛА

<Window.Resources>
    <ObjectDataProvider x:Key="LocationProvider"
        ObjectType="{x:Type srv:ServiceClient}"
        IsAsynchronous="True"MethodName="GetAssignedLocations" />
    <ObjectDataProvider
        x:Key="DevianceProvider"
        ObjectType="{x:Type srv:ServiceClient}"
        IsAsynchronous="True" MethodName="GetPercentChange">
        <ObjectDataProvider.MethodParameters>
            <system:String>Location1</system:String>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
    <ObjectDataProvider
        x:Key="CommentProvider"
        ObjectType="{x:Type srv:ServiceClient}"
        IsAsynchronous="True"
        MethodName="GetCommentByBusinessUnit">
        <ObjectDataProvider.MethodParameters>
            <system:String>Location1</system:String>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</Window.Resources>

<ComboBox Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="locations"  VerticalAlignment="Top" ItemsSource="{Binding Source={StaticResource LocationProvider}}"
              DisplayMemberPath="BuName" SelectedValuePath="BuKey"
              SelectionChanged="locations_SelectionChanged">
        <ComboBox.SelectedValue>
            <Binding Source="{StaticResource DevianceProvider}"
             Path="MethodParameters[0]"   
                 BindsDirectlyToSource="True" 
                 Mode="OneWayToSource" />
        </ComboBox.SelectedValue>
<TextBlock Name="deviance" Height="23" Margin="0,0,645,17" Width="40" Text="{Binding Source={StaticResource DevianceProvider}}" IsEnabled="False" />

<TextBox Height="23" Margin="0,0,181,17" Name="locationComments" Width="350" />
Это было полезно?

Решение

С MultiBinding вы на правильном пути.Ключевым моментом является использование MultiValueCoverter в сочетании с MultiBinding.

<MultiBinding Converter="{StaticResource Coverter_LocationMultiConverter}"
              Mode="OneWayToSource">
                <Binding Source="{StaticResource DevianceProvider}"
                         Path="MethodParameters[0]"
                         BindsDirectlyToSource="True"
                         Mode="OneWayToSource" />
                <Binding Source="{StaticResource CommentProvider}"
                         Path="MethodParameters[0]"
                         BindsDirectlyToSource="True"
                         Mode="OneWayToSource" />
            </MultiBinding>

Если раньше мы привязывались только к одному объекту, то теперь мы привязываем его к обоим ObjectDataProviders.Ключевым фактором, который позволяет нам это сделать, является конвертер:

public class LocationMultiCoverter : IMultiValueConverter
{
    #region IMultiValueConverter Members

    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        return new object[] { value, value };
    }

    #endregion
}

Поскольку нам просто нужно одно и то же значение в обоих местах, метод CovertBack довольно прост, однако я уверен, что вы можете видеть, что его можно использовать для анализа некоторых сложных вещей и передачи различных компонентов в разные места пользовательского интерфейса.

Используя этот конвертер, мы также можем опробовать небольшой образец, используя вместо этого два текстовых поля:

<Window x:Class="Sample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Sample"
    Title="Window1"
    Height="300"
    Width="300">
<Window.Resources>
    <local:LocationMultiCoverter x:Key="Coverter_LocationMultiConverter" />
</Window.Resources>
<Grid>
    <StackPanel>
        <TextBlock x:Name="uiDeviance" />
        <TextBlock x:Name="uiComment" />
        <ComboBox x:Name="uiLocations"
                  Height="23"
                  HorizontalAlignment="Left"
                  VerticalAlignment="Top"
                  SelectedValuePath="Content">
            <ComboBoxItem>1</ComboBoxItem>
            <ComboBoxItem>2</ComboBoxItem>
            <ComboBoxItem>3</ComboBoxItem>
            <ComboBoxItem>4</ComboBoxItem>
            <ComboBoxItem>5</ComboBoxItem>
            <ComboBox.SelectedValue>
                <MultiBinding Converter="{StaticResource Coverter_LocationMultiConverter}"
                              Mode="OneWayToSource">
                    <Binding ElementName="uiDeviance"
                             Path="Text"
                             BindsDirectlyToSource="True" />
                    <Binding ElementName="uiComment"
                             Path="Text"
                             BindsDirectlyToSource="True" />
                </MultiBinding>
            </ComboBox.SelectedValue>
        </ComboBox>
    </StackPanel>
</Grid>

(Преобразователь в моем примере существует в коде окна в качестве отдельного класса), и, как вы можете увидеть его тестирование, он будет обновлять оба текстовых поле при изменении выбранного Value.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top