views:

102

answers:

3

Hello.

I have a wpf control named DataPicker which has a dependency property named SelectedDate.

In simple cases it works well but there is one case where binding fails and I can't understand why: when i try to bind it inside a ListView.

For example, I have class (INotifyPropertyChanged is implemented)

public class TestClass : INotifyPropertyChanged
{
    public string Name { get; set; }
    public DateTime Date { get; set; }
}

and try to bind sample collection like

public ObservableCollection<TestClass> Items { get; set; }

which has one element in it.

Binding looks like

 <Window x:Class="Neverov.Test.Window1"
         x:Name="this"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:local="clr-namespace:Neverov.Framework;assembly=Neverov.Framework">
     <Grid>        
         <ListView ItemsSource="{Binding ElementName=this, Path=Items}">
             <ListView.ItemTemplate>
                 <DataTemplate>                     
                     <StackPanel>
                         <TextBlock Text="{Binding Name}"/>
                             <local:DatePicker SelectedDate="{Binding Date, Mode=TwoWay}"/>                             
                     </StackPanel>                     
                 </DataTemplate>
             </ListView.ItemTemplate>
        </ListView>
    </Grid>
</Window>

and Name property works fine.

inside my DatePicker date value is shown this way:

<TextBox x:Name="PART_TextBox">
    <TextBox.Text>
        <Binding Path="SelectedDate" 
                 RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type local:DatePicker}}"
                 Mode="TwoWay"
                 Converter="{StaticResource DateTimeConverter}"
                 ConverterParameter="d">
        </Binding>
    </TextBox.Text>    
</TextBox>

any ideas why this could happen?

More code of the DatePicker class: (some specific properties that I need I'll rather miss to keep code size not so large)

[TemplatePart(Name = PartPopup, Type = typeof(Popup))]
[TemplatePart(Name = PartMonthBack, Type = typeof(ButtonBase))]
[TemplatePart(Name = PartMonthForward, Type = typeof(ButtonBase))]
[TemplatePart(Name = PartDates, Type = typeof(Selector))]
[TemplatePart(Name = PartTextBox, Type = typeof(TextBox))]
[TemplatePart(Name = PartCheckBox, Type = typeof(CheckBox))]
[TemplatePart(Name = PartToggleButton, Type = typeof(ToggleButton))]
public class DatePicker : Control, INotifyPropertyChanged
{
    ...
    public static readonly DependencyProperty SelectedDateProperty =
        DependencyProperty.Register("SelectedDate",
                                    typeof(DateTime?),
                                    typeof(DatePicker),
                                    new FrameworkPropertyMetadata(null,
                                                                  FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                                                                  (sender, e) =>
                                                                  {
                                                                      var datePicker = sender as DatePicker;
                                                                      if (datePicker != null)
                                                                      {
                                                                          var oldValue = e.OldValue as DateTime?;
                                                                          DateTime selectedDateForPopup =
                                                                              datePicker.SelectedDate ??
                                                                              DateTime.Now;
                                                                          datePicker.CurrentlyViewedMonth =
                                                                              selectedDateForPopup.Month;
                                                                          datePicker.CurrentlyViewedYear =
                                                                              selectedDateForPopup.Year;
                                                                          datePicker.OnDateChanged(datePicker.SelectedDate, oldValue);                                                                              
                                                                          var popup = datePicker.GetTemplateChild(PartPopup) as Popup;
                                                                          if (popup != null)
                                                                              popup.IsOpen = false;
                                                                      }
                                                                  }));
   ... //a lot more not so important code here
}
+2  A: 

Make sure your properties throw the INotifyPropertyChanged event:

public class TestClass : INotifyPropertyChanged
{
    private DateTime date;

    public DateTime Date 
    { 
        get { return date; }
        set { date = value; NotifyPropertyChanged("Date"); } 
    }

    private void NotifyPropertyChanged(string info)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }   
}

And make your binding to the date also TwoWay:

<local:DatePicker SelectedDate="{Binding Date, Mode=TwoWay}"/>
Arcturus
they throws, of course, I just didn't mention it in post to decrease size of code in it
Neverrav
Check :).. update the answer a bit :)
Arcturus
it's set to TwoWay(
Neverrav
Can you post some more code of your DatePicker?
Arcturus
Yeah, I'll update the post.
Neverrav
It seems that your types dont match.. You use a nullable type in your control, and a non nullable DateTime in your object. Also, please try the use normal a PropertyMetadata object.. My experience is that FrameworkPropertyMetadata objects do behave rather strangely from time to time..
Arcturus
+2  A: 

Check the output window for any data binding errors..

Probable errors:

  • DataContext not set correctly.
  • ListView ItemsSource="{Binding ElementName=this, Path=Items} Isn't Items a property of the Window or a ViewModel class ?
Gishu
DataContext is set correctly (Items of the collection are binded to list box's ItemsSource), this is just a simple test app, property is part of Window class, the problem is really something deeper I think
Neverrav
and no, I see no data binding errors in output window, that's just crazy)
Neverrav
A: 

The problem is solved.

It was not in wrong bindings or other difficult and uneven stuff, but, as it was legacy code, somewhere in code programmer made a mistake.

Thank for all!

Neverrav
Don't we all make mistakes from time to time ;)
Arcturus
yeah) but I spent about two days to fix this and became rather mad)
Neverrav