Сбой MultiBinding WPF в Convertor ==> DependencyProperty.UnsetValue

Мой код дает сбой при запуске, потому что массив значений в Converter, который вызывается Multibinding, не заполнен правильным значением, но имеет значение DependencyProperty.UnsetValue.

взгляните на Convertor, а также посмотрите, где я получаю ошибку

public class ButtonColorConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            string val1 = string.Format("  {0}  ", values[0]);
            string val2 = (string)values[1];  **//Here i am getting ==> {DependencyProperty.UnsetValue}** 
            return val1.Equals(val2)
                ? Brushes.NavajoWhite
                : Brushes.White;  
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

Вы можете скачать полный код или посмотреть мои коды фрагмент, как показано ниже.

MainWindow.xaml

<Window x:Class="DataPager.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        xmlns:Local="clr-namespace:DataPager.Convertor_For_BackGround">
    <Grid>
        <Grid.Resources>
            <Local:ButtonColorConverter x:Key="currentPageSetter"/>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition Height="36*" />
            <RowDefinition Height="275*" />
        </Grid.RowDefinitions>
        <ItemsControl Name="pageControl" ItemsSource="{Binding Path=PageCollection}" Grid.Row="0">
            <ItemsControl.Template>
                <ControlTemplate TargetType="ItemsControl">
                    <Border >
                        <StackPanel>
                            <ItemsPresenter></ItemsPresenter>
                        </StackPanel>
                    </Border>
                </ControlTemplate>
            </ItemsControl.Template>
            <ItemsControl.ItemsPanel x:Uid="pageItemTemplate">
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button x:Name="pageNumberButton" Margin="3,4" Content="{Binding Path=Page_Number}">
                        <Button.Background>
                            <MultiBinding Converter="{StaticResource currentPageSetter}">
                                <Binding Path="Page_Number" />
                                <Binding Path="CurrentPage.Page_Number" /> **//This Binding not resolves properly**
                            </MultiBinding>
                        </Button.Background>
                    </Button>
                </DataTemplate>
            </ItemsControl.ItemTemplate>

        </ItemsControl>
        <TextBox Text="{Binding Path=CurrentPage.Page_Number,Mode=TwoWay, FallbackValue=asdf}" Grid.Row="1" Height="23"  Margin="79,62,257,0" Name="textBox1" VerticalAlignment="Top" Width="167" />
    </Grid>
</Window>

MainWindow.xaml.cs

 public partial class MainWindow : Window
    {
        public MainWindow()
        {


            MyPageViewModel = new PageViewModel();

            MyPageViewModel.PageCollection.Add(new PageNumberViewModel(string.Format("  {0}  ",0)));
            MyPageViewModel.PageCollection.Add(new PageNumberViewModel(string.Format("  {0}  ",1)));
            MyPageViewModel.PageCollection.Add(new PageNumberViewModel(string.Format("  {0}  ",2)));
            MyPageViewModel.PageCollection.Add(new PageNumberViewModel(string.Format("  {0}  ",3)));

            InitializeComponent();
        }

        public PageViewModel MyPageViewModel
        {
            get
            {
                return this.DataContext as PageViewModel;
            }
            set
            {
                this.DataContext = value;
            }
        }
    }

А это классы ViewModel.

PageViewModel.cs

public class PageViewModel:ViewModelBase
    {
        private ObservableCollection<PageNumberViewModel> m_pageCollection = new ObservableCollection<PageNumberViewModel>();
        private PageNumberViewModel m_currentPage = new PageNumberViewModel(string.Format("  {0}  ",0));

        public PageViewModel()
        {
            m_currentPage = new PageNumberViewModel(string.Format("  {0}  ", 1000));
        }

        public PageNumberViewModel CurrentPage 
        {
            get
            {
                return this.m_currentPage;
            }
            set
            {
                if (m_currentPage == value)
                    return;
                this.m_currentPage = value;
                base.OnPropertyChanged("CurrentPage");
            }
        }
        public ObservableCollection<PageNumberViewModel> PageCollection
        {
            get
            {
                return this.m_pageCollection;
            }
            set
            {
                if (m_pageCollection == value)
                    return;
                this.m_pageCollection = value;
                base.OnPropertyChanged("PageCollection");
            }
        }
    }

PageNumberViewModel.cs

public class PageNumberViewModel : ViewModelBase
    {
        private string m_pageNumber;

        public PageNumberViewModel()              
        {

        }
        public PageNumberViewModel(string pageNumgerArg)
        {
            this.m_pageNumber = pageNumgerArg;
        }

        public string Page_Number
        {
            get { return m_pageNumber; }
            set
            {
                if (m_pageNumber == value)
                    return;
                m_pageNumber = value;
                OnPropertyChanged("PageNumber");
            }
        }

    }

person Aryan SuryaWansi    schedule 22.07.2011    source источник
comment
Даже не углубляясь в ваш код, я настоятельно рекомендую сначала проверить, прежде чем выполнять (строку)values[1] (всегда остерегайтесь магических чисел), если a) values[] != null и b) действительно содержит объект по индексу 1 (или, по крайней мере, values.Length › 0) и c) этот объект действительно имеет желаемый тип STRING. Триггеры могут срабатывать более часто, а затем содержать значения, отличные от ожидаемых, поэтому всегда проверяйте свои массивы, прежде чем использовать их напрямую. Это может уже помочь вам предотвратить ваши исключения.   -  person Jens H    schedule 22.07.2011


Ответы (5)


Когда вы устанавливаете список в любом ItemsSource, DataContext DataTemplate для отдельных элементов будет каждым элементом списка.

Верно, что ваша привязка TextBlock работает правильно, потому что DataContext установлен на ваш основной объект: PageViewModel

Но в вашем DataTemplate для DataContext будет установлено значение PageNumberViewModel, так как это элементы вашей коллекции.

Таким образом, привязка к Path=CurrentPage.Page_Number приведет к UnsetValue, поскольку CurrentPage не является свойством PageNumberViewModel.

Надеюсь, это проясняет ситуацию!

Если вы действительно хотите привязаться к свойству CurrentPage контекста данных вашего окна, рассмотрите возможность использования привязки ElementName:

Дайте окну имя, привяжите к

<Binding ElementName="name" Path="DataContext.CurrentPage.Page_Number" />

или используйте привязку RelativeSource:

<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}" Path="DataContext.CurrentPage.Page_Number" />
person Arcturus    schedule 22.07.2011
comment
Большое вам спасибо ........ Это именно то, что я хотел ... я только что изменил путь привязки, как вы предложили ... и проблема решена ..... еще раз большое спасибо .. .... - person Aryan SuryaWansi; 22.07.2011
comment
Удивительно! Интересная проблема. Мне тоже полезно @Arcturus - person Ramankingdom; 12.12.2017

Похоже, у вас может не быть правильного DataContext для разрешения пути CurrentPage.Page_Number. Хороший способ отладки такого рода вещей — удалить путь, чтобы вы могли проверить DataContext в вашем преобразователе значений:

<Binding Path="." />

Затем установите точку останова в ButtonColorConverter и посмотрите, что именно вы пытаетесь преобразовать.

person ColinE    schedule 22.07.2011
comment
Вы можете видеть в моем коде, когда я связал это свойство CurrentPage.Page_Number со свойством TextBox Text, и оно работает нормально. это дает исключение только в том случае, если мы используем его в Multibinding с Convertor - person Aryan SuryaWansi; 22.07.2011
comment
Да, но не привязка вашего контента, Content={Binding Path=Page_Number}, не влияет на DataContext Button.Background ? - person ColinE; 22.07.2011
comment
Ya @ColinE, когда у меня есть отладка, как вы предложили ... я получаю {DataPager.ViewModel.PageNumberViewModel} вместо {DataPager.ViewModel.PageViewModel}, которое я назначил как DataContext Спасибо ..... - person Aryan SuryaWansi; 22.07.2011
comment
Плюс один за совет по отладке! - person granadaCoder; 19.10.2011

DependencyProperty.UnsetValue — это просто константа класса DependencyProperty.

Вы можете сделать что-то вроде этого:

 if (values[1] == DependencyProperty.UnsetValue)
 {
     return null;  // or default value
 }
person Simon_Weaver    schedule 13.11.2014
comment
Отличный ответ, не привязанный к одному сценарию! - person usefulBee; 30.03.2016

Я также столкнулся с этой проблемой и нашел решение в другом сообщении (https://stackoverflow.com/a/3139397/500099 ). Ключевым моментом является использование свойства FallbackValue="" следующим образом:

<MultiBinding Converter="{StaticResource StringFormatConverter}">
    <Binding Path="ResultValueControl.Min" FallbackValue=""/>
    <Binding Path="Format" />
</MultiBinding>
person user500099    schedule 19.12.2012

Я только что изменил файл MainWindow.xaml в соответствии с предложением Mr.Arcturus, и он работает нормально.

Большое вам спасибо Mr.Arcturus.

вы можете увидеть ManiWindow.xaml после изменения

<Window x:Class="DataPager.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        xmlns:Local="clr-namespace:DataPager.Convertor_For_BackGround">
    <Grid>
        <Grid.Resources>
            <Local:ButtonColorConverter x:Key="currentPageSetter"/>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition Height="36*" />
            <RowDefinition Height="275*" />
        </Grid.RowDefinitions>
        <ItemsControl Name="pageControl" ItemsSource="{Binding Path=PageCollection}" Grid.Row="0">
            <ItemsControl.Template>
                <ControlTemplate TargetType="ItemsControl">
                    <Border >
                        <StackPanel>
                            <ItemsPresenter></ItemsPresenter>
                        </StackPanel>
                    </Border>
                </ControlTemplate>
            </ItemsControl.Template>
            <ItemsControl.ItemsPanel x:Uid="pageItemTemplate">
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button x:Name="pageNumberButton" Margin="3,4" Content="{Binding Path=Page_Number}">
                        <Button.Background>
                            <MultiBinding Converter="{StaticResource currentPageSetter}">
                                <Binding Path="Page_Number" />
                                **<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}" Path="DataContext.CurrentPage.Page_Number" />** 
                            </MultiBinding>
                        </Button.Background>
                    </Button>
                </DataTemplate>
            </ItemsControl.ItemTemplate>

        </ItemsControl>
        <TextBox Text="{Binding Path=CurrentPage.Page_Number,Mode=TwoWay, FallbackValue=asdf}" Grid.Row="1" Height="23"  Margin="79,62,257,0" Name="textBox1" VerticalAlignment="Top" Width="167" />
        <Button Content="Button" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="121,110,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
    </Grid>
</Window>
person Aryan SuryaWansi    schedule 22.07.2011