Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 绑定只工作一次_C#_Wpf_Xaml_Binding_Observablecollection - Fatal编程技术网

C# 绑定只工作一次

C# 绑定只工作一次,c#,wpf,xaml,binding,observablecollection,C#,Wpf,Xaml,Binding,Observablecollection,在构造函数中,当我向绑定到TextBlock的附加属性的ObservaleCollection添加两个项时,会更新附加属性。但是,当我稍后在另一个方法中将项目添加到同一个ObservableCollection时,附加的属性不会更新 XAML: <TextBlock local:TextBlockExtensions.BindableInlines="{Binding StatusInlines}" /> public class TextBlockExtensions : Bas

在构造函数中,当我向绑定到TextBlock的附加属性的ObservaleCollection添加两个项时,会更新附加属性。但是,当我稍后在另一个方法中将项目添加到同一个ObservableCollection时,附加的属性不会更新

XAML

<TextBlock local:TextBlockExtensions.BindableInlines="{Binding StatusInlines}" />
public class TextBlockExtensions : BaseViewModel
{
    public static IEnumerable<Inline> GetBindableInlines(DependencyObject obj)
    {
        return (IEnumerable<Inline>)obj.GetValue(BindableInlinesProperty);
    }

    public static void SetBindableInlines(DependencyObject obj, IEnumerable<Inline> value)
    {
        obj.SetValue(BindableInlinesProperty, value);
    }

    public static readonly DependencyProperty BindableInlinesProperty =
        DependencyProperty.RegisterAttached("BindableInlines", typeof(IEnumerable<Inline>), typeof(TextBlockExtensions), new PropertyMetadata(null, OnBindableInlinesChanged));

    private static void OnBindableInlinesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var Target = d as TextBlock;

        if (Target != null)
        {
            Target.Inlines.Clear();
            Target.Inlines.AddRange((System.Collections.IEnumerable)e.NewValue);
        }
    }
}
public ObservableCollection<Inline> StatusInlines { get; set; } = new ObservableCollection<Inline>();
...
// works in the constructor (called twice)
StatusInlines.Add(new Run($"{ text }{ Environment.NewLine }") { ToolTip = "tooltip" });
...
// does not work later in other methods
StatusInlines.Add(new Run($"{ text }{ Environment.NewLine }") { ToolTip = "tooltip" });

TextBlockExtensions.cs

<TextBlock local:TextBlockExtensions.BindableInlines="{Binding StatusInlines}" />
public class TextBlockExtensions : BaseViewModel
{
    public static IEnumerable<Inline> GetBindableInlines(DependencyObject obj)
    {
        return (IEnumerable<Inline>)obj.GetValue(BindableInlinesProperty);
    }

    public static void SetBindableInlines(DependencyObject obj, IEnumerable<Inline> value)
    {
        obj.SetValue(BindableInlinesProperty, value);
    }

    public static readonly DependencyProperty BindableInlinesProperty =
        DependencyProperty.RegisterAttached("BindableInlines", typeof(IEnumerable<Inline>), typeof(TextBlockExtensions), new PropertyMetadata(null, OnBindableInlinesChanged));

    private static void OnBindableInlinesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var Target = d as TextBlock;

        if (Target != null)
        {
            Target.Inlines.Clear();
            Target.Inlines.AddRange((System.Collections.IEnumerable)e.NewValue);
        }
    }
}
public ObservableCollection<Inline> StatusInlines { get; set; } = new ObservableCollection<Inline>();
...
// works in the constructor (called twice)
StatusInlines.Add(new Run($"{ text }{ Environment.NewLine }") { ToolTip = "tooltip" });
...
// does not work later in other methods
StatusInlines.Add(new Run($"{ text }{ Environment.NewLine }") { ToolTip = "tooltip" });
公共类TextBlockExtensions:BaseViewModel
{
公共静态IEnumerable GetBindableInlines(DependencyObject obj)
{
返回(IEnumerable)对象GetValue(BindableInlinesProperty);
}
公共静态void SetBindableInlines(DependencyObject对象,IEnumerable值)
{
对象设置值(BindableInlinesProperty,value);
}
公共静态只读从属属性BindableInlinesProperty=
DependencyProperty.RegisterAttached(“BindableInlines”、typeof(IEnumerable)、typeof(TextBlockExtensions)、新PropertyMetadata(null、OnBindableInlinesChanged));
BindableInlineSchanged上的私有静态无效(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
var Target=d作为文本块;
如果(目标!=null)
{
Target.Inlines.Clear();
Target.Inlines.AddRange((System.Collections.IEnumerable)e.NewValue);
}
}
}
视图模型

<TextBlock local:TextBlockExtensions.BindableInlines="{Binding StatusInlines}" />
public class TextBlockExtensions : BaseViewModel
{
    public static IEnumerable<Inline> GetBindableInlines(DependencyObject obj)
    {
        return (IEnumerable<Inline>)obj.GetValue(BindableInlinesProperty);
    }

    public static void SetBindableInlines(DependencyObject obj, IEnumerable<Inline> value)
    {
        obj.SetValue(BindableInlinesProperty, value);
    }

    public static readonly DependencyProperty BindableInlinesProperty =
        DependencyProperty.RegisterAttached("BindableInlines", typeof(IEnumerable<Inline>), typeof(TextBlockExtensions), new PropertyMetadata(null, OnBindableInlinesChanged));

    private static void OnBindableInlinesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var Target = d as TextBlock;

        if (Target != null)
        {
            Target.Inlines.Clear();
            Target.Inlines.AddRange((System.Collections.IEnumerable)e.NewValue);
        }
    }
}
public ObservableCollection<Inline> StatusInlines { get; set; } = new ObservableCollection<Inline>();
...
// works in the constructor (called twice)
StatusInlines.Add(new Run($"{ text }{ Environment.NewLine }") { ToolTip = "tooltip" });
...
// does not work later in other methods
StatusInlines.Add(new Run($"{ text }{ Environment.NewLine }") { ToolTip = "tooltip" });
public observetecollection StatusInlines{get;set;}=new observetecollection();
...
//在构造函数中工作(调用两次)
添加(新运行($“{text}{Environment.NewLine}”){ToolTip=“ToolTip”});
...
//以后在其他方法中不起作用
添加(新运行($“{text}{Environment.NewLine}”){ToolTip=“ToolTip”});
BaseViewModel.cs(由angelsix提供):

公共类BaseViewModel:INotifyPropertyChanged
{
#区域保护成员
/// 
///用于属性检查的全局锁,以防止锁定表达式的不同实例。
///考虑到该检查的速度,全局锁定所有呼叫者并不是问题。
/// 
受保护对象mPropertyValueCheckLock=新对象();
#端区
/// 
///当任何子属性更改其值时激发的事件
/// 
公共事件PropertyChangedEventHandler PropertyChanged=(发送方,e)=>{};
/// 
///将此称为触发事件
/// 
/// 
公共void OnPropertyChanged(字符串名称)
{
PropertyChanged(此,新PropertyChangedEventArgs(名称));
}
#区域指挥助手
/// 
///如果未设置更新标志,则运行命令。
///如果该标志为true(表示函数已在运行),则该操作不会运行。
///如果该标志为false(表示没有运行的函数),则运行该操作。
///一旦操作完成(如果已运行),则该标志将重置为false
/// 
///定义命令是否已在运行的布尔属性标志
///如果命令尚未运行,则要运行的操作
/// 
受保护的异步任务RunCommandAsync(表达式更新标志,Func操作)
{
//锁定以确保单次进入检查
锁定(mPropertyValueCheckLock)
{
//检查flag属性是否为true(表示函数已在运行)
if(updateFlag.GetPropertyValue())
回来
//将属性标志设置为true以指示我们正在运行
updateingFlag.SetPropertyValue(true);
}
尝试
{
//运行已传递的操作
等待行动();
}
最后
{
//完成后,将属性标志设置回false
updateingFlag.SetPropertyValue(false);
}
}
/// 
///如果未设置更新标志,则运行命令。
///如果该标志为true(表示函数已在运行),则该操作不会运行。
///如果该标志为false(表示没有运行的函数),则运行该操作。
///一旦操作完成(如果已运行),则该标志将重置为false
/// 
///定义命令是否已在运行的布尔属性标志
///如果命令尚未运行,则要运行的操作
///操作返回的类型
/// 
受保护的异步任务RunCommandAsync(表达式更新标志,Func操作,T defaultValue=default(T))
{
//锁定以确保单次进入检查
锁定(mPropertyValueCheckLock)
{
//检查flag属性是否为true(表示函数已在运行)
if(updateFlag.GetPropertyValue())
返回默认值;
//将属性标志设置为true以指示我们正在运行
updateingFlag.SetPropertyValue(true);
}
尝试
{
//运行已传递的操作
返回等待操作();
}
最后
{
//完成后,将属性标志设置回false
updateingFlag.SetPropertyValue(false);
}
}
#端区
}

现在您只需设置一次
TextBlock
内联线。
您忘记订阅
INotifyCollectionChanged.CollectionChanged
事件并处理更改的项目

如果绑定源实现了
INotifyCollectionChanged
,则以下重构版本的
TextBlockExtensions
将侦听
INotifyCollectionChanged.CollectionChanged
,并相应地处理更改:

TextBlockExtensions.cs

public class TextBlockExtensions : BaseViewModel
{
  public static readonly DependencyProperty BindableInlinesProperty =
    DependencyProperty.RegisterAttached(
      "BindableInlines",
      typeof(IEnumerable<Inline>),
      typeof(TextBlockExtensions),
      new PropertyMetadata(default(IEnumerable<Inline>), OnBindableInlinesChanged));

  public static IEnumerable<Inline> GetBindableInlines(DependencyObject obj) =>
    (IEnumerable<Inline>) obj.GetValue(BindableInlinesProperty);

  public static void SetBindableInlines(DependencyObject obj, IEnumerable<Inline> value) =>
    obj.SetValue(BindableInlinesProperty, value);

  private static Dictionary<INotifyCollectionChanged, IList<WeakReference<TextBlock>>> CollectionToTextBlockMap { get; set; }

  static TextBlockExtensions()
  {
    TextBlockExtensions.CollectionToTextBlockMap =
      new Dictionary<INotifyCollectionChanged, IList<WeakReference<TextBlock>>>();
  }

  private static void OnBindableInlinesChanged(DependencyObject attachingElement, DependencyPropertyChangedEventArgs e)
  {
    if (!(attachingElement is TextBlock textBlock))
    {
      throw new ArgumentException("Attaching element must be of type 'TextBlock'.");
    }

    TextBlockExtensions.Cleanup(textBlock, e.OldValue);

    if (!(e.NewValue is IEnumerable<Inline> inlineElements))
    {
      return;
    }

    textBlock.Inlines.AddRange(inlineElements);

    if (inlineElements is INotifyCollectionChanged observableCollection)
    {
      ObserveCollectionChanges(observableCollection, textBlock);
    }
  }

  private static void Cleanup(TextBlock textBlock, object oldCollection)
  {
    textBlock.Inlines.Clear();

    if (oldCollection is INotifyCollectionChanged oldObservableCollection)
    {
      oldObservableCollection.CollectionChanged -= TextBlockExtensions.UpdateTextBlockOnCollectionChanged;
      TextBlockExtensions.CollectionToTextBlockMap.Remove(oldObservableCollection);
    }
  }

  private static void ObserveCollectionChanges(INotifyCollectionChanged observableCollection, TextBlock textBlock)
  {
    if (TextBlockExtensions.CollectionToTextBlockMap.TryGetValue(
      observableCollection,
      out IList<WeakReference<TextBlock>> boundTextBoxes))
    {
      boundTextBoxes.Add(new WeakReference<TextBlock>(textBlock));
    }
    else
    {
      observableCollection.CollectionChanged += TextBlockExtensions.UpdateTextBlockOnCollectionChanged;

      TextBlockExtensions.CollectionToTextBlockMap.Add(
        observableCollection,
        new List<WeakReference<TextBlock>>() {new WeakReference<TextBlock>(textBlock)});
    }
  }

  private static void UpdateTextBlockOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
  {
    if (TextBlockExtensions.CollectionToTextBlockMap.TryGetValue(
      sender as INotifyCollectionChanged,
      out IList<WeakReference<TextBlock>> boundTextBlocks))
    {
      var textBlockReferences = boundTextBlocks.ToList();
      foreach (WeakReference<TextBlock> boundTextBlockReference in textBlockReferences)
      {
        if (boundTextBlockReference.TryGetTarget(out TextBlock textBlock))
        {
          UpdateCollection(textBlock, e);
        }
        else
        {
          // TextBlock already collected by the GC. Cleanup.
          boundTextBlocks.Remove(boundTextBlockReference);
        }
      }
    }
  }

  private static void UpdateCollection(TextBlock textBlock, NotifyCollectionChangedEventArgs eventArgs)
  {
    switch (eventArgs.Action)
    {
      case NotifyCollectionChangedAction.Add:
        AddNewInlines(eventArgs.NewItems.OfType<Inline>(), textBlock);
        break;
      case NotifyCollectionChangedAction.Remove:
        RemoveInlines(eventArgs.OldItems.OfType<Inline>(), textBlock);
        break;
      case NotifyCollectionChangedAction.Replace:
        ReplaceInlines(eventArgs, textBlock);
        break;
      case NotifyCollectionChangedAction.Move:
        MoveInlines(eventArgs, textBlock);
        break;
      case NotifyCollectionChangedAction.Reset:
        textBlock.Inlines.Clear();
        break;
    }
  }

  private static void AddNewInlines(IEnumerable<Inline> newItems, TextBlock textBlock)
  {
    foreach (Inline newItem in newItems)
    {
      textBlock.Inlines.Add(newItem);
    }
  }

  private static void RemoveInlines(IEnumerable<Inline> removedItems, TextBlock textBlock)
  {
    foreach (Inline removedItem in removedItems)
    {
      textBlock.Inlines.Remove(removedItem);
    }
  }

  private static void ReplaceInlines(NotifyCollectionChangedEventArgs eventArgs, TextBlock textBlock)
  {
    int currentReplaceIndex = eventArgs.NewStartingIndex;
    List<Inline> replacedItems = eventArgs.OldItems.OfType<Inline>().ToList();
    List<Inline> replacementItems = eventArgs.NewItems.OfType<Inline>().ToList();
    for (int changedItemsIndex = 0; changedItemsIndex < replacementItems.Count; changedItemsIndex++)
    {
      Inline replacedItem = textBlock.Inlines.ElementAt(currentReplaceIndex++);
      Inline replacementItem = replacementItems.ElementAt(changedItemsIndex);
      textBlock.Inlines.InsertAfter(replacedItem, replacementItem);
      textBlock.Inlines.Remove(replacedItem);
    }
  }

  private static void MoveInlines(NotifyCollectionChangedEventArgs eventArgs, TextBlock textBlock)
  {
    foreach (Inline movedItem in eventArgs.OldItems.OfType<Inline>())
    {
      Inline currentItemAtNewPosition = textBlock.Inlines.ElementAt(eventArgs.NewStartingIndex);
      textBlock.Inlines.Remove(movedItem);
      textBlock.Inlines.InsertAfter(currentItemAtNewPosition, movedItem);
    }
  }
}
公共类文本