2011-04-08 3 views
2

에 통화 형식의 숫자를 표시하고 싶습니다 (바인딩에 StringFormat=c 설정). TextBox (IsKeyboardFocused==true)을 선택하면 TextBox에 초점을 맞출 때까지 서식을 없애고 싶습니다.스타일을 사용하여 TextBox 텍스트 바인딩의 매개 변수 수정

아래 코드를 붙여 넣는 방법을 찾았습니다. 이 내 문제는 바인딩이 Style 안에 지정되어 있다는 것입니다. 즉,이 작업을 수행 할 때마다 TextBox에 대한 스타일을 다시 입력해야합니다. 이상적으로 스타일을 중앙에 배치하고 TextBox마다 다시 사용하고 싶습니다. 각각에 대해 서로 다른 바인딩 대상이 있습니다.

내게는 Style을 사용하여 기존 바인딩에 매개 변수를 설정하는 방법이 있습니까? Text.Binding.StringFormat=""과 같습니까? (새로 정의 된 바인딩에 Text의 전체 값을 설정하는 것과 반대)

이 작업을 수행하는 다른 방법도 좋습니다.

코드 (이 작품 그냥 불편) :

<TextBox x:Name="ContractAmountTextBox"> 
<TextBox.Style> 
    <Style TargetType="{x:Type TextBox}">          
     <Style.Triggers> 
      <DataTrigger Binding="{Binding IsKeyboardFocused, ElementName=ContractAmountTextBox}" Value="False"> 
       <Setter Property="Text" Value="{Binding Path=ContractAmount, UpdateSourceTrigger=LostFocus, StringFormat=c}"/> 
      </DataTrigger> 
      <DataTrigger Binding="{Binding IsKeyboardFocused, ElementName=ContractAmountTextBox}" Value="True"> 
       <Setter Property="Text" Value="{Binding Path=ContractAmount, UpdateSourceTrigger=LostFocus}"/> 
      </DataTrigger> 
     </Style.Triggers> 
    </Style> 
</TextBox.Style> 

답변

6

그것은 연결된 속성으로 가능이지만, 당신이 완전히 바인딩을 교체해야 의미, 다음을 다시 넣어.

public static class TextBoxBehavior 
{ 

    #region StringFormat 

    public static string GetStringFormat(TextBox obj) 
    { 
     return (string)obj.GetValue(StringFormatProperty); 
    } 

    public static void SetStringFormat(TextBox obj, string value) 
    { 
     obj.SetValue(StringFormatProperty, value); 
    } 


    public static readonly DependencyProperty StringFormatProperty = 
     DependencyProperty.RegisterAttached(
      "StringFormat", 
      typeof(string), 
      typeof(TextBoxBehavior), 
      new UIPropertyMetadata(
      null, 
      StringFormatChanged)); 

    // Used to store the original format 
    private static readonly DependencyPropertyKey OriginalBindingPropertyKey = 
     DependencyProperty.RegisterAttachedReadOnly(
      "OriginalBinding", 
      typeof(BindingBase), 
      typeof(TextBoxBehavior), 
      new UIPropertyMetadata(null)); 

    private static void StringFormatChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) 
    { 
     TextBox textBox = o as TextBox; 
     if (textBox == null) 
      return; 

     string oldValue = (string)e.OldValue; 
     string newValue = (string)e.NewValue; 

     if (!string.IsNullOrEmpty(oldValue) && string.IsNullOrEmpty(newValue)) 
     { 
      // Update target for current binding 
      UpdateTextBindingSource(textBox); 

      // Restore original binding 
      var originalBinding = (BindingBase)textBox.GetValue(OriginalBindingPropertyKey.DependencyProperty); 
      if (originalBinding != null) 
       BindingOperations.SetBinding(textBox, TextBox.TextProperty, originalBinding); 
      textBox.SetValue(OriginalBindingPropertyKey, null); 
     } 
     else if (!string.IsNullOrEmpty(newValue) && string.IsNullOrEmpty(oldValue)) 
     { 
      // Get current binding 
      var originalBinding = BindingOperations.GetBinding(textBox, TextBox.TextProperty); 
      if (originalBinding != null) 
      { 
       // Update target for current binding 
       UpdateTextBindingSource(textBox); 

       // Create new binding 
       var newBinding = CloneBinding(originalBinding); 
       newBinding.StringFormat = newValue; 

       // Assign new binding 
       BindingOperations.SetBinding(textBox, TextBox.TextProperty, newBinding); 

       // Store original binding 
       textBox.SetValue(OriginalBindingPropertyKey, originalBinding); 
      } 
     } 
    } 

    private static void UpdateTextBindingSource(TextBox textBox) 
    { 
     var expr = textBox.GetBindingExpression(TextBox.TextProperty); 
     if (expr != null && 
      expr.ParentBinding != null && 
      (expr.ParentBinding.Mode == BindingMode.Default // Text binds two-way by default 
      || expr.ParentBinding.Mode == BindingMode.TwoWay 
      || expr.ParentBinding.Mode == BindingMode.OneWayToSource)) 
     { 
      expr.UpdateSource(); 
     } 
    } 

    private static Binding CloneBinding(Binding original) 
    { 
     var copy = new Binding 
         { 
          Path = original.Path, 
          XPath = original.XPath, 
          Mode = original.Mode, 
          Converter = original.Converter, 
          ConverterCulture = original.ConverterCulture, 
          ConverterParameter = original.ConverterParameter, 
          FallbackValue = original.FallbackValue, 
          TargetNullValue = original.TargetNullValue, 
          NotifyOnSourceUpdated = original.NotifyOnSourceUpdated, 
          NotifyOnTargetUpdated = original.NotifyOnTargetUpdated, 
          NotifyOnValidationError = original.NotifyOnValidationError, 
          UpdateSourceExceptionFilter = original.UpdateSourceExceptionFilter, 
          UpdateSourceTrigger = original.UpdateSourceTrigger, 
          ValidatesOnDataErrors = original.ValidatesOnDataErrors, 
          ValidatesOnExceptions = original.ValidatesOnExceptions, 
          BindingGroupName = original.BindingGroupName, 
          BindsDirectlyToSource = original.BindsDirectlyToSource, 
          AsyncState = original.AsyncState, 
          IsAsync = original.IsAsync, 
          StringFormat = original.StringFormat 
         }; 

     if (original.Source != null) 
      copy.Source = original.Source; 
     if (original.RelativeSource != null) 
      copy.RelativeSource = original.RelativeSource; 
     if (original.ElementName != null) 
      copy.ElementName = original.ElementName; 

     foreach (var rule in original.ValidationRules) 
     { 
      copy.ValidationRules.Add(rule); 
     } 
     return copy; 
    } 

    #endregion 
} 

사용법 :

가 여기에 신속하고 더러운 구현의

<TextBox x:Name="ContractAmountTextBox" 
     Text="{Binding Path=ContractAmount, UpdateSourceTrigger=LostFocus, StringFormat=c}"> 
    <TextBox.Style> 
     <Style TargetType="{x:Type TextBox}">          
      <Style.Triggers> 
       <Trigger Property="IsKeyboardFocused" Value="True"> 
        <Setter Property="local:TextBoxBehavior.StringFormat" Value="N"/> 
       </Trigger> 
      </Style.Triggers> 
     </Style> 
    </TextBox.Style> 
</TextBox> 

이를 사용하여, 당신은 또한

+0

감사 토마스, 그건 꽤 깔끔한 다른 텍스트 상자의 스타일을 다시 사용할 수 있습니다. 두 가지 질문이 있습니다. 스타일의 DataTrigger Binding에서 ElementName을 참조하십시오. 리소스 딕셔너리에서 스타일을 정의하고 여러 텍스트 상자에서 스타일을 다시 사용하려면 어떻게 일반화 할 수 있습니까? 두 번째는 바인딩을 수동으로 바꾸어서 예기치 않은 부작용이 생길 우려가 있다는 것입니다. Binding 모델이 향후 .NET 버전에서 확장되어 더 이상 모든 매개 변수를 복사하지 않을 수 있습니까? –

+0

ElementName에 대해서는 실제로 코드를 복사했습니다.). ElementName은 필요 없으며 DataTrigger 대신 일반적인 Trigger를 사용할 수 있습니다. 내 대답을 업데이트 할게. –

+0

네, .NET의 향후 버전에서는 작동하지 않을 수도 있습니다 ... –

관련 문제