2013-04-30 1 views
0

WPF에서 또 다른 문제가 발생했습니다.일반 데이터 바인딩은 트리거를 사용하지 않는 것으로 보입니다.

나는 사용자 정의 컨트롤 모음을 가지고 있습니다 (복합 요소, 그리드 안의 테두리로 만들어진 것 등).

나는 바인딩과 함께 트리거를 통해 그들의 Background 색상을 제어하고 있습니다. 마우스 오버시 (트리거 및 사용자 정의 IValueConverter에 의해 달성 됨) 조금 어두워지기를 원할뿐만 아니라 선택 (클릭) 할 때 색상을 변경하기를 원합니다. 후자는 일반 Setter입니다.

<Grid Width="150" Height="50" Margin="5"> 
    <Border CornerRadius="3" BorderBrush="Black" BorderThickness="0.5" > 
     <Border.Resources> 
      <local:BackgroundConverter x:Key="ColorConverter"/> 
     </Border.Resources> 
     <Border.Style> 
      <Style TargetType="Border">      
       <Style.Triggers> 
        <Trigger Property="Grid.IsMouseOver" Value="True"> 
         <Setter Property="Background" Value="{Binding Path=MyStatus, Converter={StaticResource ColorConverter}}"/> 
        </Trigger> 
        <Trigger Property="Grid.IsMouseOver" Value="False"> 
         <Setter Property="Background" Value="{Binding Path=MyStatus, Converter={StaticResource ColorConverter}}"/> 
        </Trigger> 
       </Style.Triggers> 
       <Setter Property="Background" Value="{Binding Path=MyStatus, Converter={StaticResource ColorConverter}}"/> 
      </Style> 
     </Border.Style> 
     <Grid>     
      <Grid.RowDefinitions> 
       <RowDefinition Height="0.6*"/> 
       <RowDefinition Height="0.5*"/> 
      </Grid.RowDefinitions>         
      <TextBlock Grid.Row="0" FontSize="14" TextAlignment="Center" VerticalAlignment="Center" FontWeight="Bold">      
       <Label Foreground="{Binding Path=TextColor}" Content="{Binding Path=ID}"/> 
      </TextBlock> 
      <TextBlock Grid.Row="1" FontSize="9" TextAlignment="Center" VerticalAlignment="Top" Margin="0" Padding="0"> 
       <Label Content="{Binding Path=StockName}"/> 
      </TextBlock> 
     </Grid> 
    </Border> 
</Grid> 

마우스 오버 효과는 컨트롤 중 하나를 클릭 할 때까지 올바르게 작동합니다. 트리거는 클릭하지 않은 컨트롤을 제외하고 해당 지점에서 작업을 중지합니다.

나는 약간 당황 스럽다. 트리거를 비활성화하지 않고 바인딩을 사용하려면 어떻게해야합니까?

필요한 경우 자세한 내용을 제공해 드리겠습니다.


@Rachel는

당신은 나중에 당신의 변환 코드를 게시 할 수 있습니까? IsMouseOver 속성이 변환기로 전달되는 방식을 볼 수 없으므로, 아마 변경 될 때 업데이트되지 않는 정적 값입니다. 그리고 이후 값이 트리거 될 때 값이 변경되지 않으므로 값을 재평가 할 필요가 없습니다. 당신은 IsMouseOver 및 MyStatus을 IMutliValueConverter를 사용하고 그것을 전달하는 더 좋을 수도, 그래서 어느 두 값이

변경의 나는 IMultiValueConverter을 사용하지 않은 언제 다시 평가됩니다. 그 목적을 위해 나는 IsMouseOver을 포함하는 내 자신의 "복합"객체를 만들었습니다. 이것은 배경색이 내 데이터 (항목이 선택되었거나 매핑되었는지 여부)와 마우스 오버 (배경색이 무엇이든 마우스 위로 약간 어둡게 표시됨)에서 계산되기 때문에 필요합니다. .

변환기 코드 :

public class BackgroundConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     Debug.WriteLine("BackgroundConverter.Convert()"); 
     if (!(value is StockViewBackgroundStatus)) 
     { 
      throw new ArgumentException("value"); 
     } 
     var casted = (StockViewBackgroundStatus)value; 
     if (casted.IsNone) 
     { 
      if (casted.IsMouseOver) 
      { 
       return new SolidColorBrush(Colors.Gray); 
      } 
      else 
      { 
       return CreateLinearGradient(Colors.Gray, false); 
      } 
     } 
     switch (casted.Status) 
     { 
      case StockItem.Status.Mapped: 
       { 
        return CreateLinearGradient(Color.FromRgb(83, 165, 18), casted.IsMouseOver); 
       } 
      case StockItem.Status.MappedElsewhere: 
       { 
        return CreateLinearGradient(Color.FromRgb(104, 189, 36), casted.IsMouseOver); 
       } 
      case StockItem.Status.NotMapped: 
       { 
        return CreateLinearGradient(Colors.LightGray, casted.IsMouseOver); 
       } 
      default: 
       { 
        throw new NotImplementedException(casted.Status.ToString()); 
       } 
     }    
    } 

    private static LinearGradientBrush CreateLinearGradient(Color initial, bool darker) 
    { 
     var darkened = darker ? 0.1 : 0; 
     return new LinearGradientBrush(
      Lighten(initial, 1.05 - darkened), 
      Lighten(initial, 0.95 - darkened), 
      90); 
    } 

    private static Color Lighten(Color initial, double factor) 
    { 
     Func<double, double> trunc = (value) => (Math.Max(0, Math.Min(255, value))); 
     var resulting = Color.FromRgb(
      System.Convert.ToByte(trunc(initial.R * factor)), 
      System.Convert.ToByte(trunc(initial.G * factor)), 
      System.Convert.ToByte(trunc(initial.B * factor))); 
     return resulting; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     Debug.WriteLine("BackgroundConverter.ConvertBack()"); 
     return value; 
    } 
} 

StockItem 객체

public partial class StockItem : UserControl, INotifyPropertyChanged 
{ 
    private bool _empty; 
    public StockItem() 
    { 
     InitializeComponent(); 
     DataContext = this; 
    } 

    private string _id; 
    public string ID 
    { 
     get 
     { 
      return _id; 
     } 
     set 
     { 
      _id = value; 
      RaisePropertyChanged("ID"); 
     } 

    } 

    public Brush TextColor 
    { 
     get 
     {     
      Color color = IsSelected ? Colors.White : Colors.Black; 
      return new SolidColorBrush(color); 
     } 
    } 

    private string _stockName; 
    public string StockName 
    { 
     get 
     { 
      return _stockName; 
     } 
     set 
     { 
      _stockName = value; 
      RaisePropertyChanged("StockName"); 
     } 
    } 

    StockViewBackgroundStatus _status; 
    public StockViewBackgroundStatus MyStatus 
    { 
     get 
     { 
      return new StockViewBackgroundStatus() 
      { 
       IsMouseOver = this.IsMouseOver, 
       IsNone = IsEmpty, 
       Status = MappingStatus 
      }; 
     } 
     set 
     { 
      _status = value; 
      Debug.WriteLine("in " + ID + "..."); 
      Debug.WriteLine("RaisePropertyChanged(\"IsMouseOver\")"); 
      Debug.WriteLine("RaisePropertyChanged(\"MyStatus\")"); 

      RaisePropertyChanged("IsMouseOver"); // added, but doesn't help 
      RaisePropertyChanged("MyStatus"); 
     } 
    } 

    public bool IsEmpty 
    { 
     get 
     { 
      return _empty; 
     } 
    } 

    public static StockItem EmptyStock 
    { 
     get 
     { 
      return new StockItem() 
      { 
       _empty = true, 
       ID = "none", 
       Name = String.Empty 
      }; 
     } 
    } 

    internal EventHandler Selected 
    { 
     get; 
     set; 
    } 

    private Status _mappingStatus; 
    public Status MappingStatus 
    { 
     get 
     { 
      return _mappingStatus; 
     } 
     set 
     { 
      _mappingStatus = value; 
      Debug.WriteLine("in " + ID + "..."); 
      Debug.WriteLine("RaisePropertyChanged(\"MappingStatus\")"); 
      Debug.WriteLine("RaisePropertyChanged(\"TextColor\")"); 
      RaisePropertyChanged("MappingStatus"); 
      RaisePropertyChanged("TextColor"); 

      MyStatus = new StockViewBackgroundStatus() { IsMouseOver = this.IsMouseOver, IsNone = _empty, Status = value };     

      if (value == Status.Mapped && Selected != null) 
      { 
       Selected(this, null); 
      } 
     } 
    } 

    public bool IsSelected 
    { 
     get 
     { 
      return MappingStatus == Status.Mapped; 
     } 
    } 

    public enum Status 
    {    
     Mapped, 
     MappedElsewhere, 
     NotMapped 
    } 

    protected void RaisePropertyChanged(string property) 
    { 
     if (PropertyChanged == null) 
     { 
      return; 
     } 
     PropertyChanged(this, new PropertyChangedEventArgs(property)); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 

뷰 클래스 컬렉션

(I 실제로 DataContext로 설정하고있어 하나) 캡슐화
public class TargetStocks 
{ 
    public ObservableCollection<StockItem> AllStocks 
    { 
     get; 
     set; 
    } 

    public void Add(StockItem sv, EventHandler selected) 
    { 
     if (sv == null) 
     { 
      throw new ArgumentNullException("sv"); 
     } 
     sv.MouseDown += sv_MouseDown; 
     if (selected != null) 
     { 
      sv.Selected += selected; 
     } 
     if (AllStocks == null) 
     { 
      AllStocks = new ObservableCollection<StockItem>(); 
     } 
     AllStocks.Add(sv); 
    } 

    public void AddRange(IEnumerable<StockItem> stocks, EventHandler selected) 
    { 
     foreach (var stock in stocks) 
     { 
      Add(stock, selected); 
     } 
    } 

    void sv_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e) 
    { 
     if (!(sender is StockItem)) 
     { 
      return; 
     } 
     var sv = (StockItem)sender; 
     foreach (StockItem stock in AllStocks) 
     { 
      if (stock.MappingStatus == StockItem.Status.Mapped) 
      { 
       // this seems to kill the trigger 
       stock.MappingStatus = StockItem.Status.NotMapped; 
      } 
      if (stock == sv && sv.MappingStatus != StockItem.Status.Mapped) 
      { 
       // as above 
       stock.MappingStatus = StockItem.Status.Mapped; 
      } 
     } 
    } 
} 

디버깅에 표시된 것처럼 재고 항목을 클릭하기 전에 (또는 그 중 하나의 MappingStatus이 변경되기 전에) 마우스 오버 효과는 변환기를 전혀 트리거하지 않고 작동합니다.

Convert이 전혀 호출되지 않았습니다.

MouseDown 이벤트 핸들러에 MappingStatus을 설정하여 트리거를 비활성화 (또는 분리)하는 것 같습니다.

+3

배경색을 변경하는 클릭 코드를 포함하도록 질문을 편집 할 수 있습니까? 또한, 당신의'Click' 이벤트가 바인딩의 소스 속성이나 테두리의'Background' 속성을 설정합니까? 두 번째 경우 [Depecencey Property Precedence] (http://msdn.microsoft.com/en-us/library/ms743230.aspx)는 개체 자체에 설정된 값이 스타일 또는 트리거 된 값보다 우선하도록 지정합니다. – Rachel

+0

@Rachel이 묻습니다 - 당신의'Click '은 무엇을하고 있습니까? – XAMeLi

+0

어쩌면 내가 누락되었지만 트리거가 모두 동일한 값을 반환하지 않습니까? 그들은'Status'를'Binding Path = MyStatus, Converter = {StaticResource ColorConverter}} '로 설정합니다.이 값은 기본 Setter와 같은 값이기 때문에 배경색은 마우스가 닫혔는지에 관계없이 정적으로 유지됩니다 그것 또는 아닙니다 ... – Rachel

답변

1

바인딩이 일반적인 트리거 발생의 결과로 재평가되지 않습니다.

새 바인딩 개체로 속성을 변경할 수 있지만 바인딩 자체는 트리거의 결과로 처음 사용될 때만 평가됩니다. 당신의 IsMouseOver 속성 변경의 Background 속성이 다른 Binding 객체에 하나 Binding 개체에서 변경 될 때

그래서, 그러나 그 자체를 결합하는 재평가 받고 있지 않습니다.

바인딩 된 값에 대해 PropertyChange 알림을 발생 시키면 바인딩 이 다시 평가됩니다.

테스트에서는 Debug 줄 또는 중단 점을 변환기에 추가하고 바운드 값에 대한 PropertyChanged 알림을 트리거하여 테스트합니다. 변경 알림을 수신하고 다시 평가할 때 조회수가 증가하는 것을 볼 수 있습니다.

여러 속성 중 하나가 변경 될 때 바운드 값을 계산하려면 IMultiValueConverter을 사용하십시오.

+0

다시 휴일; 그에 따라 내 질문이 업데이트되었습니다. 도움을 주셔서 감사합니다 : ( –

+0

@ KonradMorawski 감사합니다. 당신의 코드에 따라, 당신은 반드시'IMultiValueConverter'로 전환하는 것을 고려해야합니다. 왜냐하면'IsMouseOver' 나 MappingStatus가 바뀌면 바인딩이 재평가되지 않기 때문에, 또는 MyStatus' 값은 실제로 새로운 값으로 변경되지 않습니다. UI의 IsMouseOver 속성과 데이터의 MappingStatus 및 IsSelected 속성을 모두 받아들이는 IMultiValueConverter를 만들 수 있습니다. – Rachel

+0

감사합니다. 그래도 클릭 할 때까지만 (현재) 제대로 작동합니까? –

관련 문제