c# - Xamarin Forms 中的数据绑定问题
问题描述
我是 Xamarin Forms (XF) 的新手。当我尝试绑定数据时,我遇到了一个我不明白的问题。如果我通过接口(如选择器)更新任何属性,PropertyChanged
则存在。但是,如果我通过代码更新任何属性,PropertyChanged
则不存在。我尝试通过分配来修复它PropertyChanged = delegate {}
,PropertyChanged
存在但handler(this, new PropertyChangedEventArgs(propertyName));
无法更新我界面上的属性值。这是我的例子:
- 在 MainPage.xaml 中:
<Picker Grid.Row="1" Title="Select a component" ItemsSource="{Binding ComponentTree.Children}" ItemDisplayBinding="{Binding Name}" SelectedItem="{Binding SelectedGrandFatherComponent}" />
<Picker Grid.Row="2" Title="Select a component" ItemsSource="{Binding SelectedGrandFatherComponent.Children}" ItemDisplayBinding="{Binding Name}" SelectedItem="{Binding SelectedFatherComponent}" />
<Picker Grid.Row="3" x:Name="SelectedComponentPicker" Title="Select a component" ItemsSource="{Binding SelectedFatherComponent.Children}" ItemDisplayBinding="{Binding Name}" SelectedItem="{Binding SelectedComponent}" />
<ScrollView Grid.Row="4">
<interfaces:SimpleTreeView BindingContext="{Binding SelectedComponent}" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
</ScrollView>
<Label Text="{Binding SelectedComponentStructure}"></Label>
- 在 TreeCardView.xaml 中:
<Button Grid.Column="1" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Command="{Binding Appear}" BackgroundColor="Transparent" CommandParameter="{Binding Name}" />
- 在 TreeNode.cs 中(就像树中每个节点的控制器 (TreeCardView.xaml)):
public TreeNode()
{
Appear = new Command<string>((x) => ShowUp(x));
}
public static void ShowUp(string name)
{
StructureDesignViewModel instance = new StructureDesignViewModel();
StructureDesignViewModel.HandleSelectedComponent delegateIns = new StructureDesignViewModel.HandleSelectedComponent(instance.SetSelectedComponent);
delegateIns(name);
}
- 在 StructureDesignViewModel.cs(如 MainPage.xaml 的控制器)中:
public class StructureDesignViewModel : ObservableObject, INotifyPropertyChanged
{
private static readonly StructureDesignViewModel instance = new StructureDesignViewModel();
public static StructureDesignViewModel Instance
{
get
{
return instance;
}
}
public static IList<Component> Components
{
get
{
return ComponentData.Components;
}
}
TreeNode selectedGrandFatherComponent;
TreeNode selectedFatherComponent;
TreeNode selectedComponent;
string selectedComponentStructure;
public TreeNode BaseTree
{
get; set;
}
public TreeNode ComponentTree
{
get; set;
}
void GrowUp(TreeNode node, List<Component> components)
{
int len = components.Count;
for (int i = 0; i < len; i++)
{
var currentNode = node.Children.Add(new TreeNode { Name = components[i].Name, Status = components[i].Status, IsExpanded = false, Modals = components[i].Modals });
GrowUp((TreeNode)currentNode, components[i].Childs);
}
}
public StructureDesignViewModel()
{
ComponentTree = new SimpleTreeView().ViewModel.MyTree;
ComponentTree = new TreeNode { Name = "Component Root", Status = 0, IsExpanded = true };
GrowUp(ComponentTree, (List<Component>)Components);
}
public TreeNode SelectedGrandFatherComponent
{
get { return selectedGrandFatherComponent; }
set
{
if (selectedGrandFatherComponent != value)
{
selectedGrandFatherComponent = value;
OnPropertyChanged();
}
}
}
public TreeNode SelectedFatherComponent
{
get
{
if (selectedGrandFatherComponent?.Children.Count > 0)
{
selectedFatherComponent = (HMIStudio.Shared.Interfaces.TreeNode)selectedGrandFatherComponent.Children[0];
}
return selectedFatherComponent;
}
set
{
if (selectedFatherComponent != value)
{
selectedFatherComponent = value;
OnPropertyChanged();
}
}
}
public TreeNode SelectedComponent
{
get
{
if (selectedFatherComponent?.Children.Count > 0)
{
selectedComponent = (HMIStudio.Shared.Interfaces.TreeNode)selectedFatherComponent.Children[0];
}
return selectedComponent;
}
set
{
if (selectedComponent != value)
{
selectedComponent = value;
OnPropertyChanged();
}
}
}
public string SelectedComponentStructure
{
get
{
return selectedComponentStructure;
}
set
{
if (selectedComponentStructure != value)
{
Set("SelectedComponentStructure", ref selectedComponentStructure, value);
}
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
if (propertyName == "SelectedGrandFatherComponent")
{
OnPropertyChanged(nameof(SelectedFatherComponent));
}
else if (propertyName == "SelectedFatherComponent")
{
OnPropertyChanged(nameof(SelectedComponent));
}
}
}
public delegate void HandleSelectedComponent(string Name);
public void SetSelectedComponent(string name)
{
Console.WriteLine("Showing selected component {0}", name);
SelectedComponentStructure = name;
}
}
- 在 ObservableObject.cs 中:
public class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void Set<T>(string propertyName, ref T backingField, T newValue, Action beforeChange = null, Action afterChange = null)
{
if (string.IsNullOrEmpty(propertyName))
throw new ArgumentException("propertyName");
if (backingField == null && newValue == null)
return;
if (backingField != null && backingField.Equals(newValue))
return;
if (beforeChange != null)
beforeChange();
backingField = newValue;
OnPropertyChanged(propertyName);
if (afterChange != null)
afterChange();
}
}
我的程序流程:
StructureDesignViewModel
从ComponentData.Components
(树结构数据)获取数据以传递给ItemsSource
视图。- 当我选择
GrandFatherComponent
时,GrandFatherComponent.Children
是ItemSource
下一个选择器。 - 当我单击 的节点时
SimpleTreeView/SelectedComponent
,我调用函数Appear
将节点的名称分配给SelectedComponentStructure
。
我的问题SelectedComponentStructure
已更改,但界面未更新。
谢谢阅读!此致!
解决方案
结构设计视图模型
public class StructureDesignViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
string selectedComponentStructure;
public string SelectedComponentStructure
{
get
{
return selectedComponentStructure;
}
set
{
selectedComponentStructure = value;
SetPropertyValue(ref selectedComponentStructure, value);
}
}
protected void OnPropertyChanges([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected void SetPropertyValue<T>(ref T bakingFiled, T value, [CallerMemberName] string proertyName = null)
{
bakingFiled = value;
OnPropertyChanges(proertyName);
}
}
试试这个方法。。
推荐阅读
- debugging - 如何在从 GoLand 终端运行时进行调试
- jquery - 自定义选择的插件按钮
- node.js - 初始化到 oracle db 的连接以跨用 NodeJs 编写的 lambda 重用
- c# - 如何通过 .NET Core Web API 使用令牌身份验证
- android - FLAG_ACTIVITY_NEW_TASK:文档中的警告?
- ruby-on-rails - 如何在 Rails 的 wicked_pdf 中有一个动态标题?
- php - CodeIgniter 多数据库连接未从第二个数据库获取数据
- templates - 我想知道这些作业模板以哪种格式存储以及它在服务器中的位置?
- excel - 在工作表之间查找并选择单元格内容
- pdfbox - PDFBox 的内存泄漏问题