2015-01-09 2 views
3

저는 VB.net에서 별도의 프로젝트로 작성된 모든 계산 기능을 가진 엔지니어링 프로그램을 작성 중이며 현재 WPF UI를 사용하고 있습니다.WPF의 동적 조건부 서식

단위 사이에서 문자열 형식을 변경하면 문제가 발생했습니다. 예 : Imperial Units에서 4,966 lbf의 값을 가지며 변환 된 값은 22.1 kN입니다. 서로 다른 차수의 형식이므로 2 사이에 다른 형식이 있어야한다는 것을 알 수 있습니다.

현재 프로그램에 설정되어있는 것은 조건부 채색 (일반 숫자는 검은 색, 오류는 빨간색, 경고는 노란색)이며 이는 리소스 사전의 스타일을 통해 설정됩니다.

<Style x:Key="GlobalUserEditedTextBox" BasedOn="{StaticResource {x:Type TextBox}}" TargetType="TextBox"> 
    <Setter Property="Foreground" Value="{DynamicResource EditableTextColor}"/> 
    <Setter Property="FontWeight" Value="Bold"/> 
</Style> 
<Style x:Key="GlobalErrorTextBox" BasedOn="{StaticResource {x:Type TextBox}}" TargetType="TextBox"> 
    <Setter Property="Foreground" Value="{DynamicResource ErrorTextColor}"/> 
    <Setter Property="FontWeight" Value="Normal"/> 
</Style> 

프로그램에서 스타일은 변환기와 멀티 바인딩을 사용하여 선택됩니다. 다음 MultiValueConverter을

<TextBlock HorizontalAlignment="Stretch" TextAlignment="Center" Text="{Binding Path=ValueShow.TensionShow}"> 
    <TextBlock.Style> 
     <MultiBinding Converter="{StaticResource styleConverter}"> 
      <MultiBinding.Bindings> 
       <Binding RelativeSource="{RelativeSource Self}"/> 
       <Binding Path="ValueShow.TensionStatusShow"/> 
      </MultiBinding.Bindings> 
     </MultiBinding> 
    </TextBlock.Style> 
</TextBlock> 

을 그리고 : ValueShow.TensionStatusShow는 열거 값이 VB 계산 코드에서오고있다

public class StyleConverter : IMultiValueConverter 
    { 
     public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      FrameworkElement targetElement = values[0] as FrameworkElement; 
      Style _newStyle; 
      try 
      { 
       if (values[1] == null || values[1] == DependencyProperty.UnsetValue) 
        return null; 

       if ((String)values[1] == StatusColor.ErrorValue.ToString()) 
       { 
        if (values[0].GetType() == typeof(TextBox)) 
         _newStyle = (Style)targetElement.TryFindResource("GlobalErrorTextBox"); 
        else if (values[0].GetType() == typeof(TextBlock)) 
         _newStyle = (Style)targetElement.TryFindResource("GlobalErrorTextBlock"); 
        else 
         _newStyle = null; 
       } 
       else if 
       { 
        if (values[0].GetType() == typeof(TextBox)) 
         _newStyle = (Style)targetElement.TryFindResource("GlobalWarningTextBox"); 
        else if (values[0].GetType() == typeof(TextBlock)) 
         _newStyle = (Style)targetElement.TryFindResource("GlobalWarningTextBlock"); 
        else 
         _newStyle = null; 
       } 
       return _newStyle; 
      } 
      catch (Exception) 
      { 
       if (values[0].GetType() == typeof(TextBox)) 
        return (Style)targetElement.TryFindResource("GlobalUnEditableTextBox"); 
       else if (values[0].GetType() == typeof(TextBlock)) 
        return (Style)targetElement.TryFindResource("GlobalUnEditableTextBlock"); 
       else 
        return null; 
      } 
     } 

내가 무엇을 시도했다 :는 그래서 여기에 문제는 내가 원하는 것을 ValueShow.TensionStatusShow과 달리 VB 계산 방법에서 문자열 서식 지정 "규칙"을 유지하십시오. 현재 우리는 유닛 레이블에 대한 문자열을 보유하는 2 개의 리소스 사전 (제국 및 미터법)이 있습니다. 다른 문자열 형식을 설정하려고 했으므로 프로그램이 단위를 변경하면 업데이트됩니다.

제국 자원 :

<s:String x:Key="UnitsStringFormatlbfkN">F0</s:String> 
<Style TargetType="TextBox" x:Key="GlobalErrorTextBoxlbkNFormatting" BasedOn="{StaticResource GlobalErrorTextBox}"> 
     <Setter Property="Text" Value="{Binding Path=., Mode=TwoWay, StringFormat={StaticResource UnitsStringFormatlbfkN}}" /> 
    </Style> 

미터 자원

<s:String x:Key="UnitsStringFormatlbfkN">F1</s:String> 
<Style TargetType="TextBox" x:Key="GlobalErrorTextBoxlbkNFormatting" BasedOn="{StaticResource GlobalErrorTextBox}"> 
     <Setter Property="Text" Value="{Binding Path=., Mode=TwoWay, StringFormat={StaticResource UnitsStringFormatlbfkN}}" /> 
    </Style> 

그럼 난 multibinding의 세 번째 매개 변수로 lbkNFormatting을 전달하고 TryFindResource 통화에 추가 할 것입니다. 이 분명히 작동하지 않았다, 그것은 성공적으로 리소스를로드 할 수 있지만 문자열 형식을 무시합니다. 로드 된 Metric 리소스에 배경색을 추가하여 테스트했지만 문자열 형식이 무시되었습니다.

는 또한 프로그래밍 방식으로 포맷 문자열을 추가하여 MultiValueConverter의 스타일을 수정하려했지만 빠른 & 짧은 &하지 전체 간접 응답

+0

StringFormat을 정적 대신 DynamicResource로 변경해 보았습니까? – landoncz

+0

방금 ​​시도했는데 다음 오류가 발생합니다. 'DynamicResourceExtension'을 '바인딩'유형의 'StringFormat'속성에서 설정할 수 없습니다. 'DynamicResourceExtension'은 DependencyObject의 DependencyProperty에서만 설정할 수 있습니다. – user3565590

답변

2

죄송 패배 내가 보일 수없는 IsSealed 특성에 달려 있지만, 나는 당신에게 종종 간과 해답을 줄 싶었습니다. 때로는 바인딩이나 스타일이 너무 복잡 해져서 실패하기 시작하고 이유를 추적하기가 불가능 해지거나 추가 디커플링의 이점을 얻을 수있을 때 사용합니다.

거의 모든 스타일, 트리거 및 복잡한 바인딩 + MultiValueCoverters를 사용하면 소위 말하는 "첨부 된 동작"으로 다시 작성할 수 있습니다.

See this article 빠른보기. 첨부 된 속성과 추가 하위 요소라는 두 가지 방법에 유의하십시오.

사실 나는 두 가지의 장점을 동시에 사용하고 싶습니다. 메모를 남기고 싶기 때문에이 답변을 삭제하고 수다스러운 텍스트를 this article으로 옮겼습니다.

나는 왜이 스타일이 & 바인딩이 작동하지 않는지에 대한 질문에 대답하지 않는다는 것을 알고 있지만 여전히 도움이된다고 생각합니다. 당신의 스타일과 바인딩은 디버깅하기에 충분히 복잡해 보입니다. 문제는 잘못된 범위/레벨에 값을 넣으려고하면 바인딩이 매우 쉽게 분리 (분리, 재정의) 될 수 있으며 스타일 및 트리거의 setter조차도 대상과의 연결을 끊을 수 있다는 것입니다. 나는 이것이 무슨 일이 일어나고 있는지 느낀다. 그러나 나는 당신이 가까운 장래에 그것을 추적하는 것을 도울 더 많은 시간을 가지지 않을 것이다. 그러니 .. 행운을 빈다. 누군가가 당신에게 더 나은 반응을 줄 수 있기를 바랍니다.

+0

감사합니다. 이것은 매우 유용한 기능처럼 보입니다. 나는 Attached Behavior에 대해 들어 본 적이 없지만, 우리가 동적 스타일을 가지려고 노력하면서 겪었던 문제들로 인해 많은 도움이 될 것 같은데. – user3565590

+0

그래서 3 개의 속성 (SourceValue, Units 및 DisplayValue)을 모두 정적 클래스 'AttachedValue' 내에 설정했지만 텍스트 바인딩에 문제가 있습니다. 'Text = "{Binding (AttachedValue.DisplayValue), RelativeSource = Self}"컴파일러는 AttchedValue를 찾을 수 없다고 불평하고 상대 소스가 문자열을 상대 소스에 캐스팅하려고 할 때 오류가 발생합니다. 무슨 일이 벌어지고 있는지 또는 내가보기 위해 코드를 업데이트해야하는지 알고 있습니까? – user3565590

+0

@ user3565590 : 저는 메모리에서 글쓰기를했습니다. 대신'RelativeSource = {RelativeSource Self}'를 시도하십시오. '(AttachedValue.DisplayedValue)'바인딩에 대해서 네임 스페이스 접두사 접두사 즉, (myns : AttachedValue.DisplayedValue)'를 사용하여 myns를 네임 스페이스의 올바른 접두어로 바꿉니다. 그것이 작동하지 않는다면, 명시 적 Path 속성을 추가하십시오 :'Fooo = "{Binding Path = (myns : AttachedValue.DisplayedValue), ..."'WPF가 표현식을 파싱하는 방법을 알아 내지 못할 때 도움이됩니다. 때때로 발생합니다. – quetzalcoatl