2015-04-30 3 views
1

Я пытаюсь привязать к свойству зависимостей моего пользовательского элемента управления из моего пользовательского элемента управления будет работать как преобразователь продолжает бросать Обнаружили ошибку имущества незадана зависимостьUnset зависимость от привязки к свойству зависимостей

свойство зависимостей

public DateTime? DisplayedDate 
    { 
     get { return (DateTime?)base.GetValue(DisplayedDateProperty); } 
     set { base.SetValue(DisplayedDateProperty, value); } 
    } 

    public static readonly DependencyProperty DisplayedDateProperty = 
     DependencyProperty.Register("DisplayedDate", typeof(DateTime?), typeof(SideBarUser), new FrameworkPropertyMetadata() 
     { 
      BindsTwoWayByDefault = true, 
      DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, 
     }); 

XAML Связывание

<UserControl.Resources> 
    <sys:Int32 x:Key="Test">1</sys:Int32> 
    <Converters:DateCountConverter x:Key="DateCountConverter"/> 
</UserControl.Resources> 



<TextBlock DataContext="{Binding RelativeSource={RelativeSource Self}}" 
      TextAlignment="Center"> 
      <TextBlock.Text> 
       <MultiBinding Converter="{StaticResource DateCountConverter}"> 
        <Binding Path="DisplayedDate" />       
        <Binding Source="{StaticResource Test}" /> 
       </MultiBinding> 
      </TextBlock.Text> 
</TextBlock> 

И, наконец, часть он неисправный на в Coverter

DateTime date = (DateTime)values[0]; 

Все вместе дает

System.InvalidCastException 
Specified cast is not valid. 
at System.Windows.Data.MultiBindingExpression.TransferValue() 
    at System.Windows.Data.MultiBindingExpression.Transfer() 
    at System.Windows.Data.MultiBindingExpression.UpdateTarget(Boolean includeInnerBindings) 
    at System.Windows.Data.MultiBindingExpression.AttachToContext(Boolean lastChance) 
    at System.Windows.Data.MultiBindingExpression.MS.Internal.Data.IDataBindEngineClient.AttachToContext(Boolean lastChance) 
    at MS.Internal.Data.DataBindEngine.Task.Run(Boolean lastChance) 
    at MS.Internal.Data.DataBindEngine.Run(Object arg) 
    at MS.Internal.Data.DataBindEngine.OnLayoutUpdated(Object sender, EventArgs e) 
    at System.Windows.ContextLayoutManager.fireLayoutUpdateEvent() 
    at System.Windows.ContextLayoutManager.UpdateLayout() 
    at System.Windows.UIElement.UpdateLayout() 
    at System.Windows.Interop.HwndSource.SetLayoutSize() 
    at System.Windows.Interop.HwndSource.set_RootVisualInternal(Visual value) 
    at System.Windows.Interop.HwndSource.set_RootVisual(Visual value) 
    at MS.Internal.DeferredHwndSource.ProcessQueue(Object sender, EventArgs e) 

Я не могу показаться, чтобы получить эту работу для жизни меня. Я что-то упускаю? При отладке с другим экземпляром Visual Studio он приходит, что это свойство Unset DEPENDENCY

Edit: Когда я закомментируйте все и просто

<TextBlock Text="{Binding Path=DisplayedDate, RelativeSource={RelativeSource Self}}" /> 

Он работает просто отлично отображает дату отображения. Мой уровень путаницы слишком велик, чтобы справиться с прямо сейчас

EDIT EDIT: Преобразователь код

public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     DateTime? date = (DateTime?)values[0]; 
//ToDo move most of the logic inside AppointmentsViewModel class to handle date filtering 
       AppointmentsViewModel MyAppointments = new AppointmentsViewModel(); 
       String Count; 

       int SelectionType = (int)values[1]; 
       //Note To Self Make Enum 
       switch (SelectionType) 
       { 
        case 0: 
         Count = MyAppointments.Appointments.Where(x => date != null && x.Beginning.HasValue && date.HasValue 
          && x.Beginning.Value.Month == date.Value.Month 
          && x.Beginning.Value.Year == date.Value.Year).Count().ToString(); 
         break; 
        case 1: 
         Count = MyAppointments.Appointments.Where(x => date != null && x.Test.HasValue && date.HasValue 
          && x.Test.Value.Month == date.Value.Month 
          && x.Test.Value.Year == date.Value.Year).Count().ToString(); 
         break; 
        //ETC 
        default: 
         Count = MyAppointments.Appointments.Where(x => date != null && x.End.HasValue 
          && date.HasValue && x.End.Value.Month == date.Value.Month 
          && x.End.Value.Year == date.Value.Year).Count().ToString(); 
         break; 
       } 
       return Count; 
      } 

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

Можете ли вы опубликовать код для вашего конвертера? Похоже, это проблема. –

ответ

2

Есть несколько проблем с вашим кодом. Я должен был сделать некоторые предположения здесь, так что надеюсь, что я прав.

Преобразователь

Ваш конвертер предполагает, что он будет получать 2 значения определенных типов. Вы хотите быть осторожным с этим. Особенно первое значение, которое исходит от привязки, может быть DependencyProperty.UnsetValue, если привязка еще не установлена.

Таким образом, вы, вероятно, хотите, чтобы проверить, если значения правильны, прежде чем начать делать фактическое преобразование, например:

if (values.Length != 2 || !(values[0] is DateTime?)|| !(values[1] is int)) 
{ 
    return DependencyProperty.UnsetValue; 
} 

Вы не должны иметь свои исключения конвертера броска, потому что они рассматриваются как неперехваченная перспектива -time и прекратит ваше приложение, если у вас нет какого-либо глобального обработчика исключений (см. this question).

Контроль

Теперь, я полагаю, что ваша собственность DisplayedDate определяется на вашем UserControl. Если это так, то эта строка:

<TextBlock DataContext="{Binding RelativeSource={RelativeSource Self}}" 

установит DataContext к этому TextBlock, поэтому, когда вы позже пойти, чтобы получить DisplayedDate собственность, он не будет найден.Вы можете исправить это в 2-мя способами:

1) Вы используете предок-поиск связывания:

"{Binding RelativeSource={RelativeSource AncestorType=local:UserControl1}}" 

Конечно, заменить local:UserControl1 с пространством имен и имя элемента управления.

2) Необходимо определить содержание UserControl как шаблона вместо, а затем использовать {RelativeSource TemplatedParent}, который будет указывать на «владельца» шаблона, в этом случае, ваш UserControl:

<UserControl.Template> 
    <ControlTemplate> 
     <TextBlock DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" 
     TextAlignment="Center"> 
      <TextBlock.Text> 
       <MultiBinding Converter="{StaticResource DateCountConverter}"> 
        <Binding Path="DisplayedDate" /> 
        <Binding Source="{StaticResource Test}" /> 
       </MultiBinding> 
      </TextBlock.Text> 
     </TextBlock> 
    </ControlTemplate> 
</UserControl.Template> 

Просто положить это в вашем XAML вместо <TextBlock> ... </TextBlock> часть.

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

+0

Спасибо, тон, пытаясь почувствовать мой путь вокруг кода и узнать, как я иду. Это здорово и определенно дает мне кое-что, что нужно изучить и рассмотреть. Из любопытства вы случайно узнаете, почему установка текстового поля внутри шаблона позволяет ему работать, а не просто устанавливать его в своем собственном контейнере, который раньше был в стеке? – user2008572

+0

Если я правильно понимаю ваш вопрос, это не значит о том, чтобы положить текст в шаблон - разница в том, что он позволяет использовать '{RelativeSource TemplatedParent}' (вместо '{RelativeSource Self}', который укажет вам на элемент управления что текущий шаблон предназначен для - в этом случае, вашего UserControl. – vesan

Смежные вопросы