2012-01-10 3 views
1

Во-первых, извинения за все XAML. Я пробовал в течение нескольких дней, чтобы решить это, но я должен что-то упустить. Сводный вопрос заключается в том, что мое свойство зависимости UserControl не связано с привязкой к данным в коде, когда оно используется.Ошибка привязки данных в простой UserControl

Детали: У меня есть следующие простые UserControl (в его собственной DLL), где я использую ползунок 0..59 выбрать секунды, а UserControl имеет свойство Value зависимость, которая возвращает TimeSpan составленную из секунд, выбранных с помощью ползунка:

public partial class TinyTimeSpanControl : UserControl, INotifyPropertyChanged 
{ 
    public TinyTimeSpanControl() 
    { 
     InitializeComponent(); 
    } 

    private int _seconds; 

    public event PropertyChangedEventHandler PropertyChanged; 

    private void RaisePropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 
    public int Seconds 
    { 
     get { return _seconds; } 
     set 
     { 
      if (_seconds == value) 
       return; 
      _seconds = value; 
      RaisePropertyChanged("Seconds"); 

      var t = Value; 
      Value = new TimeSpan(t.Hours, t.Minutes, _seconds); 
     } 
    } 

    public TimeSpan Value 
    { 
     get { return (TimeSpan) GetValue(ValueProperty); } 
     set { SetValue(ValueProperty, value); } 
    } 

    private static void OnValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
    { 
     TinyTimeSpanControl control = obj as TinyTimeSpanControl; 
     var newValue = (TimeSpan)e.NewValue; 

     control.Seconds = newValue.Seconds; 
    } 

    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
     "Value", typeof(TimeSpan), typeof(TinyTimeSpanControl), new PropertyMetadata(OnValueChanged)); 
} 

с простым() опущены XAML:

<UserControl x:Class="WpfControlLibrary1.TinyTimeSpanControl" x:Name="root"> 
<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="Auto" /> 
    </Grid.RowDefinitions> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="Auto" /> 
     <ColumnDefinition Width="Auto" /> 
     <ColumnDefinition Width="Auto" /> 
    </Grid.ColumnDefinitions> 
    <Slider Name="SecondsSlider" 
      Width="120" 
      Height="23" 
      HorizontalAlignment="Left" 
      VerticalAlignment="Top" 
      LargeChange="5" 
      SelectionStart="0" 
      SmallChange="1" 
      Value="{Binding Path=Seconds, 
          ElementName=root}" SelectionEnd="59" Maximum="59" /> 
    <Label Name="label1" 
      Grid.Column="1" 
      Content="{Binding ElementName=SecondsSlider, 
          Path=Value}" /> 
    <Label Name="label2" 
      Grid.Column="2" 
      Content="Seconds" /> 
</Grid> 
</UserControl> 

связывание в элементе управления работает нормально.

Теперь, когда я компилирую это, а затем добавить TinyTimeSpanControl к одному из моих окон (Опущенные):

<Window x:Class="WpfControls.MainWindow" 
      xmlns:my="clr-namespace:WpfControlLibrary1;assembly=WpfControlLibrary1" 
      x:Name="root" 
      Closing="root_Closing"> 
     <Grid> 
      <Grid.RowDefinitions> 
       <RowDefinition Height="Auto" /> 
       <RowDefinition Height="Auto" /> 
       <RowDefinition Height="142*" /> 
      </Grid.RowDefinitions> 
      <Grid.ColumnDefinitions> 
       <ColumnDefinition Width="Auto" /> 
       <ColumnDefinition Width="Auto" /> 
       <ColumnDefinition Width="Auto" /> 
      </Grid.ColumnDefinitions> 
      <my:TinyTimeSpanControl Name="tinyTimeSpanControl1" 
            HorizontalAlignment="Left" 
            VerticalAlignment="Top" 
            Value="{Binding ElementName=root, 
                Path=TheTime}" /> 
      <Label Name="label1" 
        Grid.Column="1" 
        Content="{Binding ElementName=tinyTimeSpanControl1, 
            Path=Value}" /> 
      <Label Name="label2" 
        Grid.Column="2" 
        Content="{Binding ElementName=root, 
            Path=TheTime}" /> 

     </Grid> 
    </Window> 

где мое главное окно:

public partial class MainWindow : Window, INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 
    private void RaisePropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    private TimeSpan _theTime = new TimeSpan(0, 0, 33); 
    public TimeSpan TheTime 
    { 
     get 
     { 
      return _theTime; 
     } 
     set 
     { 
      if (_theTime == value) 
       return; 

      _theTime = value; 
      RaisePropertyChanged("TheTime"); 
     } 
    } 

привязки данных частично работает:

  • tinyTimeSpanControl1 изначально устанавливается в TheTime Недвижимость в мой код позади моего главного окна
  • tinyTimeSpanControl1 Обновления label1 при перемещении ползунка.

Но не работает:

  • когда ползунок перемещается, label2 остается установленным в оригинальной версии TheTime

Положив контрольную точку в на Window_closing событие показывает, что TheTime не имеет изменилось.

Я пропустил какое-то событие, которое мне нужно поднять в моем UserControl?

Благодарим и приносим извинения еще раз за все xaml (это тоже минимальный случай).

+1

Ваш код * действительно * запутанным, в первую очередь, этикетки не для простого отображения текста, а для обозначения элемента управления входного сигнала (они имеют поддержку текстового доступа и ссылаются на элемент ввода, используя свойство «Target»), вместо этого используйте «TextBlocks». Во-вторых, если вы просто хотите отображать статический текст рядом с связанным текстом, вы можете использовать 'Binding.StringFormat', чтобы добавить это. –

+0

Я использую INPC, чтобы избежать использования жестко закодированных событий, поэтому он может выглядеть немного сложнее, чем ожидалось. – Barry

ответ

2

Это проблема:

Value = new TimeSpan(t.Hours, t.Minutes, _seconds); 

Это очищает связывание вы установили в вашем окне и просто задаете значение. В коде UserControl вы не должны использовать SetValue, но SetCurrentValue, который сохраняет привязки к объекту неповрежденным.

Некоторые другие вещи могут быть выключены, а что я еще не видел ...

+0

Спасибо. Это половина проблемы. Полное решение, которое я только что обнаружил, заключается в том, чтобы добавить: 'Mode = TwoWay' к привязке' TinyTimeSpanControl' в моем основном окне. Натолкнулся, так как ваш ответ помог мне в правильном направлении. – Barry

+0

Или обновление кода позади, чтобы: 'открытые статические только для чтения DependencyProperty ValueProperty = DependencyProperty.Register ( "Value", TypeOf (TimeSpan), TypeOf (TinyTimeSpanControl), новые FrameworkPropertyMetadata (TimeSpan.Zero, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnValueChanged));' – Barry

+1

@Barry: О да, режим привязки по умолчанию - еще один отличный источник ошибок. –