내가해야 할 일에 대한 설명과 함께 내 자신의 질문에 대답 할 것입니다.
WPF가 더 잘 알고 캐쉬 할 것으로 생각하는 부분에 대해서는 계속해서 대답하는 것처럼 긴 대답입니다. DataTrigger에 무조건적인 변경이있는 경우,이 중 어떤 것도 필요하지 않습니다!
먼저 문제의 일부를 다시 정리해 보겠습니다. 다른 스타일로 다른 행을 강조 표시 할 수있는 ListView가 있습니다. 처음에는 이러한 스타일이 디버그 및 오류와 같은 기본 제공 유형이었습니다. 이 경우 ViewModel의 행 변경 스타일을 DataTriggers로 쉽게 변경하고 각 업데이트를 즉시 수행 할 수 있습니다.
사용자 정의 형광펜을 허용하도록 업그레이드하고 나면 더 이상 래치 할 속성이 없습니다. 동적으로 만든 경우에도 스타일은 알 수 없습니다.
이 문제를 해결하기 위해 HighlightingService
을 구현했습니다 (내 ServiceLocator
을 사용하고 IHightlightingServce
지원 인스턴스를 요청하면 언제든지 발견 할 수 있음). 이 서비스는 중요한 프로퍼티와 메소드의 수를 구현합니다
public ObservableCollection<IHighlighter> Highlighters { get; private set; }
public IHighlighterStyle IsHighlighted(ILogEntry logEntry)
{
foreach (IHighlighter highlighter in Highlighters)
{
if (highlighter.IsMatch(logEntry))
{
return highlighter.Style;
}
}
return null;
}
형광펜 컬렉션 공개적으로 액세스 할 수 있으므로를, 그 수집의 사용자가/방법을 추가 제거 구현하는 나의 필요를 부정/추가 항목을 제거 할 수 있음을 허용하기로 결정 . 그러나 서비스의 생성자에서 내부 IHighlighter
레코드가 변경되었는지를 알아야하기 때문에 해당 등록자의 CollectionChanged
속성에 관찰자를 등록하고 다른 콜백을 등록하여 항목 추가/제거에 반응합니다. 그러면 서비스를 시작할 수 있습니다 특정 INotifyCollectionChanged
이벤트. 이 모든으로
[...]
// Register self as an observer of the collection.
Highlighters.CollectionChanged += HighlightersCollectionChanged;
}
private void HighlightersCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (var newItem in e.NewItems)
{
System.Diagnostics.Debug.Assert(newItem != null);
System.Diagnostics.Debug.Assert(newItem is IHighlighter);
if (e.NewItems != null
&& newItem is IHighlighter
&& newItem is INotifyPropertyChanged)
{
// Register on OnPropertyChanged.
IHighlighter highlighter = newItem as IHighlighter;
Trace.WriteLine(string.Format(
"FilterService detected {0} added to collection and binding to its PropertyChanged event",
highlighter.Name));
(newItem as INotifyPropertyChanged).PropertyChanged += CustomHighlighterPropertyChanged;
}
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (var oldItem in e.OldItems)
{
System.Diagnostics.Debug.Assert(oldItem != null);
System.Diagnostics.Debug.Assert(oldItem is IHighlighter);
if (e.NewItems != null
&& oldItem is IHighlighter
&& oldItem is INotifyPropertyChanged)
{
// Unregister on OnPropertyChanged.
IHighlighter highlighter = oldItem as IHighlighter;
Trace.WriteLine(string.Format(
"HighlightingService detected {0} removed from collection and unbinding from its PropertyChanged event",
highlighter.Name));
(oldItem as INotifyPropertyChanged).PropertyChanged -= CustomHighlighterPropertyChanged;
}
}
}
}
private void CustomHighlighterPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (sender is IHighlighter)
{
IHighlighter filter = (sender as IHighlighter);
Trace.WriteLine(string.Format("FilterServer saw some activity on {0} (IsEnabled = {1})",
filter.Name, filter.Enabled));
}
OnPropertyChanged(string.Empty);
}
은, 지금은 사용자가 등록 된 하이 라이터를 변경할 때마다 알고,하지만 난 아무것도에 트리거를 연결할 수 없다는 사실을 고정하지 않은, 그래서 변화를 반영 할 수 표시 스타일.
나는이 분류의 XAML 유일한 방법을 찾을 수 없습니다, 그래서 난 내 ListView에 포함 된 사용자 정의 컨트롤 제작 :
- 그것은 할당 : 이것은 몇 가지를 않습니다을
public partial class LogMessagesControl : UserControl
{
private IHighlightingService highlight { get; set; }
public LogMessagesControl()
{
InitializeComponent();
highlight = ServiceLocator.Instance.Get<IHighlightingService>();
if (highlight != null && highlight is INotifyPropertyChanged)
{
(highlight as INotifyPropertyChanged).PropertyChanged += (s, e) => UpdateStyles();
}
messages.ItemContainerStyleSelector = new HighlightingSelector();
}
private void UpdateStyles()
{
messages.ItemContainerStyleSelector = null;
messages.ItemContainerStyleSelector = new HighlightingSelector();
}
}
새 HighlightingSelector
을 ItemContainerStyleSelector
(ListView는 messages
)으로 지정하십시오.
- 또한 ViewModel 인 HighlighterService의
PropertyChanged
이벤트에 자신을 등록합니다.
- 변경 사항을 감지하면
ItemContainerStyleSelector
의 현재 인스턴스 인 HighlightingSelector
을 대체합니다 (Bea Costa가 필요로하는 웹에 주석이 있으므로 먼저 null로 바뀝니다). 그래서
는, 지금 필요한 모든 계정에 소요 HighlightingSelector 인 현재 강조 선택 (I가 그들이,이 재건 될 것이다 변경해야합니다) 알고, 내가 너무 일에 대해 걱정할 필요가 없습니다 많은). HighlightingSelector
은 등록 된 형광펜을 반복하며 (활성화 된 경우) 스타일을 등록합니다. 나는 이것들을 비싸기 때문에 재 구축 할 때 Dictionary
에 캐시하고, 사용자가 수동으로 상호 작용을 한 시점에서만 빌드되기 때문에이 일을 앞당기는 데 드는 비용이 눈에 띄지 않습니다.
런타임에서 염두에 두는 레코드에 HighlightingSelector.SelectStyle
이 전달되면 적절한 스타일 (사용자의 원래 강조 표시 환경 설정을 기반으로 함)이 반환됩니다.
public class HighlightingSelector : StyleSelector
{
private readonly Dictionary<IHighlighter, Style> styles = new Dictionary<IHighlighter, Style>();
public HighlightingSelector()
{
IHighlightingService highlightingService = ServiceLocator.Instance.Get<IHighlightingService>();
if (highlightingService == null) return;
foreach (IHighlighter highlighter in highlightingService.Highlighters)
{
if (highlighter is TypeHighlighter)
{
// No need to create a style if not enabled, should the status of a highlighter
// change, then this collection will be rebuilt.
if (highlighter.Enabled)
{
Style style = new Style(typeof (ListViewItem));
DataTrigger trigger = new DataTrigger();
trigger.Binding = new Binding("Type");
trigger.Value = (highlighter as TypeHighlighter).TypeMatch;
if (highlighter.Style != null)
{
if (highlighter.Style.Background != null)
{
trigger.Setters.Add(new Setter(Control.BackgroundProperty,
new SolidColorBrush((Color) highlighter.Style.Background)));
}
if (highlighter.Style.Foreground != null)
{
trigger.Setters.Add(new Setter(Control.ForegroundProperty,
new SolidColorBrush((Color) highlighter.Style.Foreground)));
}
}
style.Triggers.Add(trigger);
styles[highlighter] = style;
}
}
}
}
public override Style SelectStyle(object item, DependencyObject container)
{
ILogEntry entry = item as ILogEntry;
if (entry != null)
{
foreach (KeyValuePair<IHighlighter, Style> pair in styles)
{
if (pair.Key.IsMatch(entry) && pair.Key.Enabled)
{
return pair.Value;
}
}
}
return base.SelectStyle(item, container);
}
}
datatriggers는 INotifyValueChanged 발표 속성에 대해 올바르게 작동하지만 사용자가 정의한 속성에 대해서는 속성이 없습니다. 현재 구현에서는 IValueConverter를 사용하여 내장 또는 사용자 정의와 관계없이 적절한 앞 / 뒤 색상을 얻습니다. 그러나 이미 표시된 색상은 내용에 변화가 없기 때문에 색상을 새로 고칩니다 (내용 변경). 기존 버튼 상태를 제 위치에 유지하고 기본 상태 (예 : 경고) 중 하나를 전환하면 잘 고쳐집니다. –