2015-01-31 2 views
0

Я сейчас занимаюсь учебным проектом. Он должен преобразовывать числа в разные строки. Heres преобразованный элемент управления, а в нижней части я использую его в своем главном окне. Итак, первая проблема заключается в том, что я хочу создать экземпляр конвертера на основе значения, которое я передаю OutputFormatProperty, поэтому в этом случае я создаю конвертер, который должен быть типом OctalConverter, но вместо этого я получаю значение по умолчанию, почему? Другое дело, что я не буду изменять InputValue в конвертере, привязывая его к CurrentValue, который работает с NotifyPropertyChanged, но похоже, что это не так.Когда применяется свойство зависимостей?

public partial class ConverterDisplay : UserControl { 

    private const int DEFAULT_INPUT_VALUE = 0; 
    private readonly ObservableCollection <DisplayField> _displayFields; 
    private AbstractNumberConverter _converter; 

    public static readonly DependencyProperty InputValueProperty = DependencyProperty.Register (
     "InputValue", 
     typeof(int), 
     typeof(ConverterDisplay), 
     new PropertyMetadata (DEFAULT_INPUT_VALUE)); 

    public static readonly DependencyProperty OutputFormatProperty = DependencyProperty.Register (
     "OutputFormat", 
     typeof(NumberSystems), 
     typeof(ConverterDisplay), 
     new FrameworkPropertyMetadata (NumberSystems.Binary)); 


    public int InputValue { 
     get { 
      return (int) GetValue (InputValueProperty); 
     } 
     set { 
      SetValue (InputValueProperty, value); 
      UpdateDisplay(); 
     } 
    } 
    public NumberSystems OutputFormat { 
     get { 
      return (NumberSystems) GetValue (OutputFormatProperty); 

     } 
     set { 
      SetValue (OutputFormatProperty, value); 
     } 
    } 

    public ObservableCollection <DisplayField> DisplayFields { 
     get { return _displayFields; } 
    } 

    public ConverterDisplay() { 
     _displayFields = new ObservableCollection<DisplayField>(); 
     InitializeComponent(); 
     CreateConverter(); 
    } 

    private void UpdateDisplay() { 
     var convertedNumberString = _converter.GetString (InputValue); 

     if (_displayFields.Count > convertedNumberString.Length) 
      ResetDisplayFields(); 

     while (_displayFields.Count < convertedNumberString.Length) 
      AddDisplayField(); 

     UpdateValues (convertedNumberString); 
    } 

    private void UpdateValues (string convertedString) { 
     if (_displayFields.Count == 0) return; 

     for (int i = 0; i < _displayFields.Count; i++) { 
      _displayFields [i].NumberValue = convertedString [i]; 
     } 
    } 

    private void AddDisplayField() { 
     _displayFields.Insert (
      0, 
      new DisplayField ((int)OutputFormat, _displayFields.Count)); 
    } 

    private void ResetDisplayFields() { 
     _displayFields.Clear(); 
    } 

    private void CreateConverter() { 
     switch (OutputFormat) { 
      case NumberSystems.Binary: 
       _converter = new BinaryConverter(); 
       break; 
      case NumberSystems.Octal: 
       _converter = new OctalConverter(); 
       break; 
      case NumberSystems.Hexadecimal: 
       _converter = new HexadecimalConverter(); 
       break; 
     } 
    } 
} 

public enum NumberSystems { 
    Binary = 2, 
    Octal = 8, 
    Hexadecimal = 16 
} 

А потом в главном окне я пытаюсь использовать этот контроль

<converters:ConverterDisplay x:Name="octConverter" 
           InputValue="{Binding ElementName=Window,Path=CurrentValue}" 
           OutputFormat="Octal"/> 

Только в случае

public int CurrentValue { 
     get { return _currentValue; } 
     set { 
      if (value == _currentValue) 
       return; 
      ValidateNewValue (value); 
      OnPropertyChanged(); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    [NotifyPropertyChangedInvocator] 
    protected virtual void OnPropertyChanged ([CallerMemberName] string propertyName = null) { 
     PropertyChanged?.Invoke (this, new PropertyChangedEventArgs (propertyName)); 
    } 

============ ===============

Редактировать # 1

Мне не очень нравится это решение, но я создал публичный метод в ConverterDisplay для создания конвертера, он вызывается после того, как MainWindow инициализирован, поэтому теперь преобразователи верны. Другое дело, как связать мой метод UpdateDisplay с InputValueProperty? Я нашел подтверждение, что оно получает правильное значение, но я не могу понять, как я могу запустить этот метод без создания статического материала.

ответ

0

Что касается Вашей второй проблемы (связывание метода UpdateDisplay к InputValueProperty: В общем, это не самая лучшая идея, чтобы вызвать любой метод в инкубаторе свойства зависимостей, так как этот сеттер никогда не вызывается при использовании привязки для заполнения значение свойства зависимостей в данных , как было указано at MSDN:..

процессор WPF XAML использует методы системного свойства для зависимости свойства при загрузке двоичных XAML и обработки атрибутов, которые свойства зависимостей Это эффективно обходит собственности оберток при реализации пользовательских зависимостей Свойс у вас должно быть аккаунта для этого поведения, и вы должны избегать размещения какого-либо другого кода в вашей обертке свойств, кроме методов системы свойств GetValue и SetValue.

Вместо создать метод обратного вызова, который вызывается всякий раз, когда изменения содержания InputValue «s, и вызовите UpdateDisplay оттуда:

public static readonly DependencyProperty InputValueProperty = DependencyProperty.Register (
    "InputValue", 
    typeof(int), 
    typeof(ConverterDisplay), 
    new PropertyMetadata (DEFAULT_INPUT_VALUE, InputValueChangedCallback)); 


private static void InputValueChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) 
{ 
    var userControl = dependencyObject as ConverterDisplay; 
    if (userControl != null) 
     userControl.UpdateDisplay(); 
} 
+0

Спасибо! То, как я это сделаю, я думаю, что я также воспользуюсь этим решением для создания разных NumberConverters, когда значение в OutputFormatProperty изменится, поэтому у меня нет вызова из кода внутри MainWinow:] – yoger