C# 刷新WPF中子控件的DataContext
我们有一个客户机-服务器应用程序,它需要动态构建视图。服务器将把XAML字符串和数据(DctionaryC# 刷新WPF中子控件的DataContext,c#,wpf,xaml,inheritance,datacontext,C#,Wpf,Xaml,Inheritance,Datacontext,我们有一个客户机-服务器应用程序,它需要动态构建视图。服务器将把XAML字符串和数据(Dctionary)一起发送到客户机,然后客户机将根据收到的XAML字符串构建视图,并将数据绑定到视图 以下是示例XAML字符串: <StackPanel> <TextBox> <TextBox.Text> <Binding RelativeSource="{{RelativeSource
<StackPanel>
<TextBox>
<TextBox.Text>
<Binding RelativeSource="{{RelativeSource Self}}" Path="DataContext"
Converter="{{StaticResource fieldBindingConverter}}" ConverterParameter="ID_Id"
UpdateSourceTrigger="PropertyChanged">
</Binding>
</TextBox.Text>
</TextBox>
<TextBox>
<TextBox.Text>
<Binding RelativeSource="{{RelativeSource Self}}" Path="DataContext"
Converter="{{StaticResource fieldBindingConverter}}" ConverterParameter="ID_Name"
UpdateSourceTrigger="PropertyChanged">
</Binding>
</TextBox.Text>
</TextBox>
</StackPanel>
当两个文本框从窗口继承DataContext时,Text属性绑定到字典。
绑定转换器“fieldBindingConverter”使用具有键的ConverterParameter从字典中获取正确的值
因此,在首次构建视图时,这两个文本框将相应地显示“1”和“John”
当新数据到达客户端时,问题就出现了
new Dictionary<string, string>
{
{"ID_Id", "2"},
{"ID_Name", "Peter"}
};
事实上,文本框的DataContext仍然缓存旧数据值
TextBox似乎在第一次初始化时只获取其父DataContext的一个副本,然后才使用该本地副本
在这种情况下,拥有一个ViewModel并实现INotifyPropertyChanged似乎并不容易,因为键“ID_XX”在不同的视图中可能会有所不同,并且它会发生变化;很难为这种动态特性定义一个模型类(我可能错了)
如果每次新数据到达时都创建一个新的托管窗口(并且设置了DataContext),那么它确实可以正常工作,因为所有文本框的DataContext都将为新的托管窗口派生新数据
有人知道如何让文本框“刷新”其DataContext以获取父窗口上的新设置并“刷新”绑定吗?在WPF中,我们通常不会将
窗口的DataContext
设置为这样的一个数据类型对象。。。然而,这是可能的。相反,我们通常创建一个特定的类,该类包含需要显示的所有属性,并且如您所述,实现了INotifyPropertyChanged
接口。在您的情况下,我们可以在UI中绑定类型为Staff
的属性:
public string Staff
{
get { return staff; }
set { staff = value; NotifyPropertyChanged("Staff"); }
}
然后在XAML中:
<Window>
<StackPanel>
<TextBox Text="{Binding Staff.Id}"/>
<TextBox Text="{Binding Staff.Name}"/>
</StackPanel>
</Window>
然后,您可以像这样填写CustomObject
:
CustomObjects = new ObservableCollection<CustomObject>();
CustomObject customObject = new CustomObject();
foreach (KeyValuePair<string, string> entry in data)
{
if (entry.Key == "ID_Id") // Assuming this always comes first
{
customObject = new CustomObject();
customObject.Id = int.Parse(entry.Value);
}
...
else if (entry.Key == "ID_Name") // Assuming this always comes lasst
{
customObject.Name = entry.Value;
customObjects.Add(customObject);
}
}
...
<ListBox ItemsSource="{Binding CustomObjects}">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type DataTypes:CustomObject}">
<StackPanel>
<TextBox Text="{Binding Id}"/>
...
<TextBox Text="{Binding Name}"/>
</StackPanel>
</DataTemplate DataType="{x:Type DataTypes:CustomObject}">
</ListBox.ItemTemplate>
</Window>
CustomObjects=新的ObservableCollection();
CustomObject CustomObject=新的CustomObject();
foreach(数据中的KeyValuePair条目)
{
if(entry.Key==“ID\u ID”)//假设这总是第一位的
{
customObject=新的customObject();
customObject.Id=int.Parse(entry.Value);
}
...
else if(entry.Key==“ID\u Name”)//假设这总是lasst
{
customObject.Name=entry.Value;
customObjects.Add(customObject);
}
}
...
...
现在你可以争辩说你不能这样做,或者因为这个原因你不想这么做,但是到了最后,你必须这样做来解决你的问题。
< P>你可以考虑创建一个从了望台BeCopEngress类继承的自定义观察字典< t,u>类。我已经这样做了,虽然这是一些工作,以获得扭结出来,它已成为我最宝贵的自定义类之一。一些简短的代码作为建议:
/// <summary>Dictionary changed event handler</summary>
/// <param name="sender">The dictionary</param>
/// <param name="e">The event arguments</param>
public delegate void NotifyDictionaryChangedEventHandler(object sender, NotifyDictionaryChangedEventArgs e);
public class CollectionDictionary<TKey, TValue> : ObservableCollection<TValue>
{
#region Fields
private ConcurrentDictionary<TKey, TValue> collectionDictionary =
new ConcurrentDictionary<TKey, TValue>();
#endregion
/// <summary>
/// Initializes a new instance of the CollectionDictionary class
/// </summary>
public CollectionDictionary()
{
}
/// <summary>
/// Initializes a new instance of the CollectionDictionary class
/// </summary>
/// <param name="collectionDictionary">A dictionary</param>
public CollectionDictionary(Dictionary<TKey, TValue> collectionDictionary)
{
for (int i = 0; i < collectionDictionary.Count; i++)
{
this.Add(collectionDictionary.Keys.ToList()[i], collectionDictionary.Values.ToList()[i]);
}
}
/// <summary>
/// Initializes a new instance of the CollectionDictionary class
/// </summary>
/// <param name="collectionDictionary">A concurrent dictionary</param>
public CollectionDictionary(ConcurrentDictionary<TKey, TValue> collectionDictionary)
{
this.collectionDictionary = collectionDictionary;
}
#region Events
/// <summary>The dictionary has changed</summary>
public event NotifyDictionaryChangedEventHandler DictionaryChanged;
#endregion
#region Indexers
/// <summary> Gets the value associated with the specified key. </summary>
/// <param name="key"> The key of the value to get or set. </param>
/// <returns> Returns the Value property of the System.Collections.Generic.KeyValuePair<TKey,TValue>
/// at the specified index. </returns>
public TValue this[TKey key]
{
get
{
TValue tValue;
if (this.collectionDictionary.TryGetValue(key, out tValue) && (key != null))
{
return this.collectionDictionary[key];
}
else
{
return tValue;
}
}
////set
////{
//// this.collectionDictionary[key] = value;
//// string tKey = key.ToString();
//// string tValue = this.collectionDictionary[key].ToString();
//// KeyValuePair<TKey, TValue> genericKeyPair = new KeyValuePair<TKey, TValue>(key, value);
//// List<KeyValuePair<TKey, TValue>> keyList = this.collectionDictionary.ToList();
//// for (int i = 0; i < keyList.Count; i++)
//// {
//// if (genericKeyPair.Key.ToString() == keyList[i].Key.ToString())
//// {
//// RemoveAt(i, String.Empty);
//// Insert(i, value.ToString(), String.Empty);
//// }
//// }
////}
}
/// <summary>
/// Gets the value associated with the specific index
/// </summary>
/// <param name="index">The index</param>
/// <returns>The value at that index</returns>
public new TValue this[int index]
{
get
{
if (index > (this.Count - 1))
{
return default(TValue);
}
else
{
return this.collectionDictionary.ToList()[index].Value;
}
}
}
#endregion
/// <summary>
/// Dictionary has changed. Notify any listeners.
/// </summary>
/// <param name="e">Evevnt arguments</param>
protected virtual void OnDictionaryChanged(NotifyDictionaryChangedEventArgs e)
{
if (this.DictionaryChanged != null)
{
this.DictionaryChanged(this, e);
}
}
///字典已更改事件处理程序
///字典
///事件参数
公共委托void NotifyDictionaryChangedEventHandler(对象发送方,NotifyDictionaryChangedEventArgs e);
公共类集合字典:ObservableCollection
{
#区域字段
私有ConcurrentDictionary集合字典=
新的ConcurrentDictionary();
#端区
///
///初始化CollectionDictionary类的新实例
///
公共收藏词典()
{
}
///
///初始化CollectionDictionary类的新实例
///
///字典
公共收集字典(字典收集字典)
{
for(int i=0;i<Window>
<StackPanel>
<TextBox Text="{Binding Staff.Id}"/>
<TextBox Text="{Binding Staff.Name}"/>
</StackPanel>
</Window>
public class CustomObject
{
public int Id { get; set; }
public string Name { get; set; }
...
}
...
Dictionary<string, string> data = new Dictionary<string, string>
{
{"ID_Id", "1"},
{"ID_Name", "John"}
...
};
...
// Implement the `INotifyPropertyChanged` interface on this property
public ObservableCollection<CustomObject> CustomObjects { get; set; }
...
CustomObjects = new ObservableCollection<CustomObject>();
CustomObject customObject = new CustomObject();
foreach (KeyValuePair<string, string> entry in data)
{
if (entry.Key == "ID_Id") // Assuming this always comes first
{
customObject = new CustomObject();
customObject.Id = int.Parse(entry.Value);
}
...
else if (entry.Key == "ID_Name") // Assuming this always comes lasst
{
customObject.Name = entry.Value;
customObjects.Add(customObject);
}
}
...
<ListBox ItemsSource="{Binding CustomObjects}">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type DataTypes:CustomObject}">
<StackPanel>
<TextBox Text="{Binding Id}"/>
...
<TextBox Text="{Binding Name}"/>
</StackPanel>
</DataTemplate DataType="{x:Type DataTypes:CustomObject}">
</ListBox.ItemTemplate>
</Window>
/// <summary>Dictionary changed event handler</summary>
/// <param name="sender">The dictionary</param>
/// <param name="e">The event arguments</param>
public delegate void NotifyDictionaryChangedEventHandler(object sender, NotifyDictionaryChangedEventArgs e);
public class CollectionDictionary<TKey, TValue> : ObservableCollection<TValue>
{
#region Fields
private ConcurrentDictionary<TKey, TValue> collectionDictionary =
new ConcurrentDictionary<TKey, TValue>();
#endregion
/// <summary>
/// Initializes a new instance of the CollectionDictionary class
/// </summary>
public CollectionDictionary()
{
}
/// <summary>
/// Initializes a new instance of the CollectionDictionary class
/// </summary>
/// <param name="collectionDictionary">A dictionary</param>
public CollectionDictionary(Dictionary<TKey, TValue> collectionDictionary)
{
for (int i = 0; i < collectionDictionary.Count; i++)
{
this.Add(collectionDictionary.Keys.ToList()[i], collectionDictionary.Values.ToList()[i]);
}
}
/// <summary>
/// Initializes a new instance of the CollectionDictionary class
/// </summary>
/// <param name="collectionDictionary">A concurrent dictionary</param>
public CollectionDictionary(ConcurrentDictionary<TKey, TValue> collectionDictionary)
{
this.collectionDictionary = collectionDictionary;
}
#region Events
/// <summary>The dictionary has changed</summary>
public event NotifyDictionaryChangedEventHandler DictionaryChanged;
#endregion
#region Indexers
/// <summary> Gets the value associated with the specified key. </summary>
/// <param name="key"> The key of the value to get or set. </param>
/// <returns> Returns the Value property of the System.Collections.Generic.KeyValuePair<TKey,TValue>
/// at the specified index. </returns>
public TValue this[TKey key]
{
get
{
TValue tValue;
if (this.collectionDictionary.TryGetValue(key, out tValue) && (key != null))
{
return this.collectionDictionary[key];
}
else
{
return tValue;
}
}
////set
////{
//// this.collectionDictionary[key] = value;
//// string tKey = key.ToString();
//// string tValue = this.collectionDictionary[key].ToString();
//// KeyValuePair<TKey, TValue> genericKeyPair = new KeyValuePair<TKey, TValue>(key, value);
//// List<KeyValuePair<TKey, TValue>> keyList = this.collectionDictionary.ToList();
//// for (int i = 0; i < keyList.Count; i++)
//// {
//// if (genericKeyPair.Key.ToString() == keyList[i].Key.ToString())
//// {
//// RemoveAt(i, String.Empty);
//// Insert(i, value.ToString(), String.Empty);
//// }
//// }
////}
}
/// <summary>
/// Gets the value associated with the specific index
/// </summary>
/// <param name="index">The index</param>
/// <returns>The value at that index</returns>
public new TValue this[int index]
{
get
{
if (index > (this.Count - 1))
{
return default(TValue);
}
else
{
return this.collectionDictionary.ToList()[index].Value;
}
}
}
#endregion
/// <summary>
/// Dictionary has changed. Notify any listeners.
/// </summary>
/// <param name="e">Evevnt arguments</param>
protected virtual void OnDictionaryChanged(NotifyDictionaryChangedEventArgs e)
{
if (this.DictionaryChanged != null)
{
this.DictionaryChanged(this, e);
}
}
/// <summary> Adds a key/value pair to the
/// System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue>
/// if the key does not already exist, or updates a key/value pair in the
/// System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue>
/// if the key already exists. </summary>
/// <param name="key"> The key to be added or whose value should be updated </param>
/// <param name="addValueFactory">The function used to generate a value for an absent key</param>
/// <param name="updateValueFactory">The function used to generate a new value for an
/// existing key based on the key's existing value</param>
/// <returns> The new value for the key. This will be either be the result of addValueFactory
/// (if the key was absent) or the result of updateValueFactory (if the key was
/// present). </returns>
public TValue AddOrUpdate(TKey key, Func<TKey, TValue> addValueFactory, Func<TKey, TValue, TValue> updateValueFactory)
{
TValue value;
value = this.collectionDictionary.AddOrUpdate(key, addValueFactory, updateValueFactory);
if (this.collectionDictionary.TryGetValue(key, out value))
{
ArrayList valueList = new ArrayList() { value };
ArrayList keyList = new ArrayList() { key };
NotifyDictionaryChangedEventArgs e = new NotifyDictionaryChangedEventArgs(
NotifyCollectionChangedAction.Add,
valueList,
keyList);
this.Add(value, string.Empty);
this.OnDictionaryChanged(e);
}
return value;
}
/// <summary> Returns an enumerator that iterates through the
/// ObservableExtendedCollection<TValue>. </summary>
/// <returns> An enumerator for the
/// underlying ObservableExtendedCollection<TKey,TValue>. </returns>
public new IEnumerator<TValue> GetEnumerator()
{
return (IEnumerator<TValue>)base.GetEnumerator();
}
/// <summary> Returns an enumerator that iterates through the
/// System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue>. </summary>
/// <returns> An enumerator for the
/// System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue>. </returns>
/// <param name="collectionFlag">Flag indicates to return the collection enumerator</param>
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator(bool collectionFlag = true)
{
return this.collectionDictionary.GetEnumerator();
}